Skip to content

Instantly share code, notes, and snippets.

@diatche
Last active October 22, 2020 21:03
Show Gist options
  • Select an option

  • Save diatche/164f451834729af8a40e4c3a9d3fcbbd to your computer and use it in GitHub Desktop.

Select an option

Save diatche/164f451834729af8a40e4c3a9d3fcbbd to your computer and use it in GitHub Desktop.

Revisions

  1. diatche revised this gist Oct 22, 2020. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion swedbank-csv.py
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,4 @@
    #!/bin/python
    #!/bin/python3

    # Converts Swedbank CSV format into a CSV table
    # format which is easier for automated processing.
  2. diatche revised this gist Oct 22, 2020. 1 changed file with 11 additions and 5 deletions.
    16 changes: 11 additions & 5 deletions swedbank-csv.py
    Original file line number Diff line number Diff line change
    @@ -2,17 +2,23 @@

    # Converts Swedbank CSV format into a CSV table
    # format which is easier for automated processing.

    #
    # Usage:
    #
    # 1. Save file as swedbank-csv.py and open terminal in folder location.
    # 2. In termial: python3 swedbank-csv.py -i <path to source CSV>
    # 3. For more info, run: python3 swedbank-csv.py --help
    #
    # Example:
    #
    # Date,Beneficiary/Payer,Details,Amount,Currency,Transaction type,Balance
    # 01.01.2019,,Opening balance,,EUR,AS,41.7
    # 06.01.2019,Janis Pipars,Parskaitijums,-10.0,EUR,IZP,
    # 10.01.2019,,Kartes mēneša maksa 12.2019,-1.41,EUR,KOM,
    # 31.01.2019,,Closing balance,,EUR,LS,20.0

    #
    # Works with Swedbank Latvia CSV format as at 23 Oct 2020.

    #
    # Author: Pavel Diatchenko <[email protected]>
    # Licence: MIT

    @@ -22,7 +28,7 @@

    parser = argparse.ArgumentParser(
    description=(
    'Converts Swedbank CSV format into a CSV table'
    'Converts Swedbank CSV format into a CSV table '
    'format which is easier for automated processing.\n\n'
    'Works with Swedbank Latvia CSV format as at 23 Oct 2020.\n\n'
    'Author: Pavel Diatchenko <[email protected]>\n'
  3. diatche created this gist Oct 22, 2020.
    153 changes: 153 additions & 0 deletions swedbank-csv.py
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,153 @@
    #!/bin/python

    # Converts Swedbank CSV format into a CSV table
    # format which is easier for automated processing.

    # Example:

    # Date,Beneficiary/Payer,Details,Amount,Currency,Transaction type,Balance
    # 01.01.2019,,Opening balance,,EUR,AS,41.7
    # 06.01.2019,Janis Pipars,Parskaitijums,-10.0,EUR,IZP,
    # 10.01.2019,,Kartes mēneša maksa 12.2019,-1.41,EUR,KOM,
    # 31.01.2019,,Closing balance,,EUR,LS,20.0

    # Works with Swedbank Latvia CSV format as at 23 Oct 2020.

    # Author: Pavel Diatchenko <[email protected]>
    # Licence: MIT

    import csv
    import argparse
    from pathlib import Path

    parser = argparse.ArgumentParser(
    description=(
    'Converts Swedbank CSV format into a CSV table'
    'format which is easier for automated processing.\n\n'
    'Works with Swedbank Latvia CSV format as at 23 Oct 2020.\n\n'
    'Author: Pavel Diatchenko <[email protected]>\n'
    'Licence: MIT'
    )
    )
    parser.add_argument(
    '-i',
    '--source',
    type=str,
    required=True,
    help='Source CSV file path.',
    )
    parser.add_argument(
    '-o',
    '--destination',
    type=str,
    help='Destination CSV file path.',
    )
    parser.add_argument(
    '-s',
    '--suffix',
    type=str,
    help='Destination CSV file suffix. If destination file is ommited, this suffix is added to the source file name',
    )
    parser.add_argument(
    '-d',
    '--delimiter',
    type=str,
    help='Source CSV column delimiter.',
    )
    parser.add_argument(
    '--verbose',
    dest='verbose',
    action='store_true',
    help='Verbose mode.',
    )

    parser.set_defaults(
    suffix='-parsed',
    delimiter=';',
    verbose=False,
    )
    args = parser.parse_args()
    verbose = bool(args.verbose)

    source_path = Path(args.source).expanduser()
    if verbose: print(f'source_path: "{source_path}"')

    destination_path = ''
    if not bool(args.destination):
    # Polyfill with_stem (new in Python 3.9)
    def with_stem(p, stem):
    ext = p.suffix
    return p.with_name(f'{stem}{ext}')

    if verbose: print(f'suffix: "{args.suffix}"')
    destination_path = with_stem(source_path, source_path.stem + args.suffix)
    else:
    destination_path = Path(args.destination).expanduser()
    if verbose: print(f'destination_path: "{destination_path}"')

    delimiter = args.delimiter
    if verbose: print(f'delimiter: "{delimiter}"')

    BALANCE_KEY = 'Balance'
    AMOUNT_KEY = 'Amount'
    DEBIT_CREDIT_KEY = 'Debit/Credit'
    DEBIT = 'D'
    CREDIT = 'K'
    TYPE_KEY = 'Transaction type'
    BALANCE_TYPES = {'AS', 'LS'}
    REMOVE_TYPES = set(['K2'])
    INPUT_HEADERS = ['Client account', 'Row type', 'Date', 'Beneficiary/Payer', 'Details', AMOUNT_KEY, 'Currency', DEBIT_CREDIT_KEY, 'Transfer reference', TYPE_KEY, 'Reference number', 'Document number', '']
    OUTPUT_HEADERS = ['Date', 'Beneficiary/Payer', 'Details', AMOUNT_KEY, 'Currency', TYPE_KEY, BALANCE_KEY]

    with open(source_path, newline='') as source:
    reader = csv.reader(source, delimiter=delimiter, quotechar='"')
    destination_path.touch()
    with open(destination_path, 'w', newline='') as destination:
    writer = csv.writer(destination, delimiter=',', quotechar='"')
    if verbose: print('begin')
    for i, row in enumerate(reader):
    if i == 0:
    assert row == INPUT_HEADERS, 'Unexpected input headers'
    writer.writerow(OUTPUT_HEADERS)
    continue
    row_dict = {}
    for key, val in zip(INPUT_HEADERS, row):
    row_dict[key] = val

    # filter types
    if row_dict[TYPE_KEY] in REMOVE_TYPES:
    continue

    # map amount sign
    amount = float(str(row_dict[AMOUNT_KEY]).replace(',', '.'))
    debit_credit = row_dict[DEBIT_CREDIT_KEY]
    is_debit = debit_credit == DEBIT
    is_credit = debit_credit == CREDIT
    if not is_debit and not is_credit:
    continue
    if is_debit:
    amount = -amount

    # map balance
    balance = ''
    if row_dict[TYPE_KEY] in BALANCE_TYPES:
    balance = amount
    amount = ''
    else:
    balance = ''

    out_dict = {
    AMOUNT_KEY: amount,
    BALANCE_KEY: balance
    }
    outrow = []
    outval = None
    for key in OUTPUT_HEADERS:
    if key in out_dict:
    outval = out_dict[key]
    elif key in row_dict:
    outval = row_dict[key]
    outrow.append(outval)
    writer.writerow(outrow)
    if verbose: print(outrow)
    if verbose: print('end')