def parse_record(self, line): """Parse given transaction line and return StatementLine object """ if (self.statement.account_id == None): self.statement.account_id = line[0].replace(" ", "") stmtline = super(BelfiusParser, self).parse_record(line) stmtline.trntype = 'DEBIT' if stmtline.amount < 0 else 'CREDIT' stmtline.bank_account_to = BankAccount(line[12], line[4].replace(" ", "")) return stmtline
def parse_record(self, line): """Parse given transaction line and return StatementLine object """ self.statement.account_id = line[0].replace(" ", "") #self.statement.account_to = line[5].replace(" ", "") stmtline = super(NewBParser, self).parse_record(line) stmtline.id = generate_transaction_id(stmtline) stmtline.trntype = 'DEBIT' if stmtline.amount < 0 else 'CREDIT' stmtline.bank_account_to = BankAccount(None, line[5].replace(" ", "")) return stmtline
def parse_transaction( self, line: List[Optional[str]]) -> Optional[StatementLine]: # line[2] contains the account number if self.statement.account_id: assert self.statement.account_id == line[2],\ "Only one account is allowed; previous account: {}, \ this line's account: {}" .format(self.statement.account_id, line[2]) else: self.statement.account_id = line[2] assert line[5] in ['Af', 'Bij'] if line[5] == 'Af': amount: Optional[str] = line[self.mappings['amount']] line[self.mappings['amount']] =\ '-' + (amount if isinstance(amount, str) else '') if line[self.mappings['bank_account_to']]: line[self.mappings['payee']] =\ "{} ({})".format(line[self.mappings['payee']], line[self.mappings['bank_account_to']]) else: line[self.mappings['memo']] =\ "{}, {}".format(line[self.mappings['payee']], line[self.mappings['memo']]) line[self.mappings['payee']] = None # Python 3 needed stmt_line: StatementLine = super().parse_record(line) # Remove zero-value notifications if stmt_line.amount == 0: return None # Determine some fields not in the self.mappings # A hack but needed to use the adjust method stmt_line.__class__ = StatementLine stmt_line.adjust(self.unique_id_set) if stmt_line.amount < 0: stmt_line.trntype = "DEBIT" else: stmt_line.trntype = "CREDIT" if stmt_line.bank_account_to: stmt_line.bank_account_to = \ BankAccount(bank_id=None, acct_id=stmt_line.bank_account_to) return stmt_line
def test_ofxWriter(self): # Create sample statement: statement = Statement("BID", "ACCID", "LTL") statement.lines.append(StatementLine( "1", datetime(2012, 2, 12), "Sample 1", 15.4)) line = StatementLine("2", datetime(2012, 2, 12), "Sample 2", 25.0) line.payee = '' line.bank_account_to = BankAccount("SNORAS", "LT1232") line.bank_account_to.branch_id = "VNO" statement.lines.append(line) # Create writer: writer = ofx.OfxWriter(statement) # Set the generation time so it is always predictable writer.genTime = datetime(2012, 3, 3, 0, 0, 0) assert prettyPrint(writer.toxml()) == SIMPLE_OFX
def parse_record(self, transaction: Transaction) -> StatementLine: """Parse given transaction line and return StatementLine object """ logger.debug('transaction:\n' + pformat(transaction, indent=4)) stmt_line = None # Use str() to prevent rounding errors bank_account_to = transaction.data.get('customer_reference') amount = Decimal(str(transaction.data['amount'].amount)) memo = transaction.data['transaction_details'] memo = memo.replace("\n", '') memo = memo.replace(transaction.data['customer_reference'], '', 1) memo = memo.replace(transaction.data['extra_details'], '', 1).strip() memo = memo if memo != '' else 'UNKNOWN' payee = None if transaction.data['customer_reference'] != ''\ and transaction.data['extra_details'] != '': payee = "{1} ({0})".format(transaction.data['customer_reference'], transaction.data['extra_details']) date = transaction.data['date'] # Remove zero-value notifications if amount != 0: stmt_line = StatementLine(date=date, memo=memo, amount=amount) stmt_line.id = \ generate_unique_transaction_id(stmt_line, self.unique_id_set) m = re.match(r'([0-9a-f]+)(-\d+)?$', stmt_line.id) assert m, "Id should match hexadecimal digits, \ optionally followed by a minus and a counter: '{}'".format(stmt_line.id) if m.group(2): counter = int(m.group(2)[1:]) # include counter so the memo gets unique stmt_line.memo = stmt_line.memo + ' #' + str(counter + 1) stmt_line.payee = payee if bank_account_to: stmt_line.bank_account_to = \ BankAccount(bank_id=None, acct_id=bank_account_to) return stmt_line
def test_ofxWriter(self) -> None: # Create sample statement: statement = Statement("BID", "ACCID", "LTL") statement.lines.append( StatementLine("1", datetime(2012, 2, 12), "Sample 1", Decimal("15.4"))) line = StatementLine("2", datetime(2012, 2, 12), "Sample 2", Decimal("25.0")) line.payee = "" line.bank_account_to = BankAccount("SNORAS", "LT1232") line.bank_account_to.branch_id = "VNO" line.currency = Currency("USD") line.orig_currency = Currency("EUR", Decimal("3.4543")) statement.lines.append(line) # Create writer: writer = ofx.OfxWriter(statement) # Set the generation time so it is always predictable writer.genTime = datetime(2012, 3, 3, 0, 0, 0) assert prettyPrint(writer.toxml()) == SIMPLE_OFX
def parse_value(self, value, field): if field == "bank_account_to": return BankAccount("", value) else: return super().parse_value(value, field)
def parse_value(self, value, field): value = value.strip() if value else value if field == "bank_account_to": return BankAccount("", value) else: return super().parse_value(value, field)
def parse_record(self, line: List[str]) -> Optional[StatementLine]: """Parse given transaction line and return StatementLine object """ try: logger.debug('header count: %d; line #%d: %s', len(self.header), self.cur_record, line) # First record(s) must be the header if len(self.header) >= 1: # Remove it since it need not be checked anymore hdr = self.header.pop(0) line = list(filter(None, line)) logger.debug('header: %s', hdr) assert line == hdr,\ "Expected: {}\ngot: {}".format(hdr, line) return None # line[self.ACCOUNT] contains the account number if self.statement.account_id: assert self.statement.account_id == \ line[self.ACCOUNT],\ "Only one account is allowed; previous account: {}, \ this line's account: {}" .format(self.statement.account_id, line[self.ACCOUNT]) else: self.statement.account_id = line[self.ACCOUNT] assert line[self.CD] in ['D', 'C'],\ "Element {} is not D/C in line {}".format(self.CD, str(line)) if line[self.CD] == 'D': line[self.mappings['amount']] =\ '-' + line[self.mappings['amount']] if line[self.mappings['bank_account_to']]: line[self.mappings['payee']] =\ "{} ({})".format(line[self.mappings['payee']], line[self.mappings['bank_account_to']]) # Python 3 needed stmt_line: StatementLine = super().parse_record(line) # Remove zero-value notifications if stmt_line.amount == 0: return None # Determine some fields not in the self.mappings # A hack but needed to use the adjust method stmt_line.__class__ = StatementLine stmt_line.adjust(self.unique_id_set) if stmt_line.amount < 0: stmt_line.trntype = "DEBIT" else: stmt_line.trntype = "CREDIT" if stmt_line.bank_account_to: stmt_line.bank_account_to = \ BankAccount(bank_id=None, acct_id=stmt_line.bank_account_to) except Exception as e: raise ParseError(self.cur_record, str(e)) return stmt_line
def parse_record(self, line): """Parse given transaction line and return StatementLine object """ self.line_nr += 1 if line[0] == HEADER_START: return None elif len(line) != LINELENGTH: raise ParseError( self.line_nr, 'Wrong number of fields in line! ' + 'Found ' + str(len(line)) + ' fields ' + 'but should be ' + str(LINELENGTH) + '!') # Check the account id. Each line should be for the same account! if self.statement.account_id: if line[0] != self.statement.account_id: raise ParseError( self.line_nr, 'AccountID does not match on all lines! ' + 'Line has ' + line[0] + ' but file ' + 'started with ' + self.statement.account_id) else: self.statement.account_id = line[0] # Check the currency. Each line should be for the same currency! if self.statement.currency: if line[3] != self.statement.currency: raise ParseError( self.line_nr, 'Currency does not match on all lines! ' + 'Line has ' + line[3] + ' but file ' + 'started with ' + self.statement.currency) else: self.statement.currency = line[3] stmt_ln = super(KbcBeParser, self).parse_record(line) if line[12] != None and line[12] != '': stmt_ln.bank_account_to = BankAccount('', line[12]) elif line[6].startswith('AUTOMATISCH SPAREN'): payee_match = re.match( 'AUTOMATISCH SPAREN\s+\d\d\-\d\d\s+(?:NAAR|VAN) (\w\w\d\d(?: \d{4}){3})', line[6]) if payee_match == None: raise ParseError( self.line_nr, 'Cannot parse savings info. (' + line[6] + ')') stmt_ln.bank_account_to = BankAccount('', payee_match.group(1)) if stmt_ln.payee == None or stmt_ln.payee == '': if line[6].startswith('BETALING AANKOPEN VIA '): payee_match = re.match( 'BETALING AANKOPEN VIA (?:.+), (.+) MET KBC\-(?:BANK|DEBET)KAART', line[6]) if payee_match == None: raise ParseError( self.line_nr, 'Cannot parse maestro/bancontact transaction info. (' + line[6] + ')') stmt_ln.payee = payee_match.group(1) elif line[6].startswith('AUTOMATISCH SPAREN'): payee_match = re.match( 'AUTOMATISCH SPAREN\s+\d\d\-\d\d\s+(?:NAAR|VAN) (\w\w\d\d(?: \d{4}){3})', line[6]) if payee_match == None: raise ParseError( self.line_nr, 'Cannot parse savings info. (' + line[6] + ')') stmt_ln.payee = payee_match.group(1) return stmt_ln