File: dnbLV.py

package info (click to toggle)
ofxstatement-plugins 20181208
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 4,064 kB
  • sloc: python: 7,004; xml: 1,027; makefile: 135; sh: 84
file content (108 lines) | stat: -rw-r--r-- 3,927 bytes parent folder | download | duplicates (6)
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
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
"""Parser implementation for DNB generated statement reports"""

import re
import logging
from xml.etree import ElementTree

from ofxstatement.parser import StatementParser
from ofxstatement.plugin import Plugin
from ofxstatement.statement import Statement, StatementLine

CARD_PURCHASE_RE = re.compile(r".* Pirkums - .*? - par (\d\d\/\d\d\/\d\d\d\d)", re.U | re.M)

class dnbLVStatementParser(StatementParser):
    date_format = "%Y-%m-%d"

    statement = None
    fin = None  # file input stream

    debug = (logging.getLogger().getEffectiveLevel() == logging.DEBUG)

    def __init__(self, fin):
        self.statement = Statement()
        self.fin = fin

    def split_records(self):
        xml = ElementTree.parse(self.fin)
        xml = xml.getroot()

        namespaces = {'ns': xml.tag[1:].partition("}")[0]}
        statement = xml.find('ns:Statement', namespaces=namespaces)

        period = statement.find('ns:Period', namespaces=namespaces)
        self.statement.start_date = self.parse_datetime(period.find('ns:StartDate', namespaces=namespaces).text)
        self.statement.end_date = self.parse_datetime(period.find('ns:EndDate', namespaces=namespaces).text)

        account = statement.find('ns:AccountSet', namespaces=namespaces)
        if not self.statement.account_id:
            self.statement.account_id = account.find('ns:AccNo', namespaces=namespaces).text

        transactions = account.find('ns:CcyStmt', namespaces=namespaces)
        self.statement.start_balance = self.parse_float(transactions.find('ns:OpenBal', namespaces=namespaces).text)

        all_transactions = transactions.findall('ns:TrxSet', namespaces=namespaces)

        return all_transactions

    def parse_record(self, line):
        # Namespace stuff
        namespaces = {'ns': line.tag[1:].partition("}")[0]}

        # Get all fields
        type_code = line.find('ns:TypeCode', namespaces=namespaces).text
        date = line.find('ns:BookDate', namespaces=namespaces).text
        c_or_d = line.find('ns:CorD', namespaces=namespaces).text
        amount = line.find('ns:AccAmt', namespaces=namespaces).text
        id = line.find('ns:BankRef', namespaces=namespaces).text
        note = line.find('ns:PmtInfo', namespaces=namespaces).text

        # Payee name
        payee_name = None
        payee = line.find('ns:CPartySet', namespaces=namespaces)
        if payee:
            payee_account = payee.find('ns:AccHolder', namespaces=namespaces)
            if payee_account:
                payee_name = payee_account.find('ns:Name', namespaces=namespaces).text

        # Create statement line
        stmt_line = StatementLine(id, self.parse_datetime(date), note, self.parse_float(amount))
        stmt_line.payee = payee_name

        # Credit & Debit stuff
        stmt_line.trntype = "DEP"
        if c_or_d == 'D':
            stmt_line.amount = -stmt_line.amount
            stmt_line.trntype = "DEBIT"

        # Various types
        if type_code == 'MEMD':
            stmt_line.trntype = "SRVCHG"
        elif type_code == 'OUTP':
            stmt_line.trntype = "PAYMENT"

        # Check if paid by card
        m = CARD_PURCHASE_RE.match(stmt_line.memo)
        if m:
            # this is an electronic purchase. extract some useful
            # information from memo field
            date = m.group(1).split('/')
            date = '%s-%s-%s' % (date[2], date[1], date[0])
            stmt_line.date_user = self.parse_datetime(date)

        # DEBUG
        if self.debug:
            print(stmt_line, stmt_line.trntype)

        return stmt_line

    def parse_float(self, value):
        return value if isinstance(value, float) else float(value.replace(',', '.'))


class DnbLVPlugin(Plugin):
    """Latvian DNB CSV"""

    def get_parser(self, fin):
        parser = dnbLVStatementParser(fin)
        parser.statement.currency = self.settings.get('currency', 'EUR')
        return parser