summaryrefslogtreecommitdiff
path: root/transaction_details.py
blob: baa6ef30679d69598d61640b36a861c70404f047 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# see https://github.com/raphaelm/python-fints/pull/8

# https://www.db-bankline.deutsche-bank.com/download/MT940_Deutschland_Structure2002.pdf
DETAIL_KEYS = {
    '': 'Geschäftsvorfall-Code',
    '00': 'Buchungstext',
    '10': 'Primanota',
    '20': 'Verwendungszweck',
    '30': 'Auftraggeber BLZ',
    '31': 'Auftraggeber Kontonummer',
    '32': 'Auftraggeber Name',
    '34': 'Rücklastschriften',
    '35': 'Empfänger: Name',
    '60': 'Zusätzl. Verwendungszweckangaben',
}

# https://www.hettwer-beratung.de/sepa-spezialwissen/sepa-technische-anforderungen/sepa-geschäftsvorfallcodes-gvc-mt-940/
VERWENDUNGSZWECK_KEYS = {
    '': 'Verwendungszweck',
    'IBAN': 'Auftraggeber IBAN',
    'BIC': 'Auftraggeber BIC',
    'EREF': 'End to End Referenz',
    'MREF': 'Mandatsreferenz',
    'CRED': 'Auftraggeber Creditor ID',
    'PURP': 'Purpose Code',
    'SVWZ': 'Verwendungszweck',
    'MDAT': 'Mandatsdatum',
    'ABWA': 'Abweichender Auftraggeber',
    'ABWE': 'Abweichender Empfänger',
    'SQTP': 'FRST / ONE / OFF /RECC',
    'ORCR': 'SEPA Mandatsänderung: alte SEPA CI',
    'ORMR': 'SEPA Mandatsänderung: alte SEPA Mandatsreferenz',
    'DDAT': 'SEPA Settlement Tag für R- Message',
    'KREF': 'Kundenreferenz',
    'DEBT': 'Debtor Identifier bei SEPA Überweisung',
    'COAM': 'Compensation Amount',
    'OAMT': 'Original Amount',
}


def parse_transaction_details(details):
    detail_str = ''.join(d.strip() for d in details.splitlines())
    detail_str = detail_str[3:]
    result = dict(map(lambda k: [k,None], DETAIL_KEYS.values()))
    result.update(dict(map(lambda k: [k,None], VERWENDUNGSZWECK_KEYS.values())))
    pre_result = {}
    for segment in detail_str.split('?'):
        pre_result[segment[0:2]] = segment[2:]
    for key, value in pre_result.items():
        if key in DETAIL_KEYS:
            result[DETAIL_KEYS[key]] = value
        else:
            if key == '33':
                result[DETAIL_KEYS['32']] = (result[DETAIL_KEYS['32']]  or '') + value
            elif key.startswith('2'):
                result[DETAIL_KEYS['20']] = (result[DETAIL_KEYS['20']] or '') + value
            else:
                raise ValueError('Found Key ?{}, which is not documented'.format(key))
    post_result = {}
    segment_type = None
    text = ''
    for index, char in enumerate(result['Verwendungszweck']):
        if char == '+' and result['Verwendungszweck'][index-4:index] in VERWENDUNGSZWECK_KEYS:
            if segment_type:
                post_result[segment_type] = text[:-4]
                text = ''
            else:
                text = ''
            segment_type = result['Verwendungszweck'][index-4:index]
        else:
            text += char
    if segment_type:
        post_result[segment_type] = text
    else:
        post_result[''] = text
    for key, value in post_result.items():
        result[VERWENDUNGSZWECK_KEYS[key]] = value
    return result