Browse Source

[10.0] Better parse camt groupped transactions (#131)

* correctly parse entries with multiple transactions

Our bank does it.  Care has been taken not to break cases where
Ntry/NtryDtls/TxDtls isn't used: if any piece of information isn't found
on these nodes, the matching information from the Ntry is used.  Most
often the entry has a sum or a summary and the transaction details are
more precise and specific, so it makes sense to use their contents
rather than its.

* more complete unit tests for camt parser

This checks the whole output data of the parser against its expected
output.

* add a test case that checks TxDtls decoding

* special case for Ntrys without TxDtls

* CO-12 - Date Import BVR

* FIX tests

* CO-1232 Fixed issues with CAMT parser tests
pull/158/head
ecino 7 years ago
committed by Maxence Groine
parent
commit
c4dc160eda
  1. 58
      account_bank_statement_import_camt/models/parser.py
  2. 26
      account_bank_statement_import_camt/test_files/golden-camt053-txdtls.pydata
  3. 45
      account_bank_statement_import_camt/test_files/golden-camt053.pydata
  4. 214
      account_bank_statement_import_camt/test_files/test-camt053-txdtls
  5. 45
      account_bank_statement_import_camt/tests/test_import_bank_statement.py

58
account_bank_statement_import_camt/models/parser.py

@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Class to parse camt files.""" """Class to parse camt files."""
# © 2013-2016 Therp BV <http://therp.nl> # © 2013-2016 Therp BV <http://therp.nl>
# Copyright 2017 Open Net Sàrl
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import re import re
from lxml import etree from lxml import etree
@ -46,7 +47,7 @@ class CamtParser(models.AbstractModel):
break break
def parse_transaction_details(self, ns, node, transaction): def parse_transaction_details(self, ns, node, transaction):
"""Parse transaction details (message, party, account...)."""
"""Parse TxDtls node."""
# message # message
self.add_value_from_node( self.add_value_from_node(
ns, node, [ ns, node, [
@ -64,9 +65,13 @@ class CamtParser(models.AbstractModel):
ns, node, [ ns, node, [
'./ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref', './ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref',
'./ns:Refs/ns:EndToEndId', './ns:Refs/ns:EndToEndId',
'./ns:Ntry/ns:AcctSvcrRef'
], ],
transaction, 'ref' transaction, 'ref'
) )
amount = self.parse_amount(ns, node)
if amount != 0.0:
transaction['amount'] = amount
# remote party values # remote party values
party_type = 'Dbtr' party_type = 'Dbtr'
party_type_node = node.xpath( party_type_node = node.xpath(
@ -107,10 +112,11 @@ class CamtParser(models.AbstractModel):
ns, account_node[0], './ns:Othr/ns:Id', transaction, ns, account_node[0], './ns:Othr/ns:Id', transaction,
'account_number' 'account_number'
) )
transaction['data'] = etree.tostring(node)
def parse_transaction(self, ns, node):
"""Parse transaction (entry) node."""
transaction = {}
def parse_entry(self, ns, node):
"""Parse an Ntry node and yield transactions"""
transaction = {'name': '/', 'amount': 0} # fallback defaults
self.add_value_from_node( self.add_value_from_node(
ns, node, './ns:BkTxCd/ns:Prtry/ns:Cd', transaction, ns, node, './ns:BkTxCd/ns:Prtry/ns:Cd', transaction,
'transfer_type' 'transfer_type'
@ -121,27 +127,30 @@ class CamtParser(models.AbstractModel):
ns, node, './ns:BookgDt/ns:Dt', transaction, 'execution_date') ns, node, './ns:BookgDt/ns:Dt', transaction, 'execution_date')
self.add_value_from_node( self.add_value_from_node(
ns, node, './ns:ValDt/ns:Dt', transaction, 'value_date') ns, node, './ns:ValDt/ns:Dt', transaction, 'value_date')
transaction['amount'] = self.parse_amount(ns, node)
details_node = node.xpath(
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns})
if details_node:
self.parse_transaction_details(ns, details_node[0], transaction)
if not transaction.get('name'):
amount = self.parse_amount(ns, node)
if amount != 0.0:
transaction['amount'] = amount
self.add_value_from_node( self.add_value_from_node(
ns, node, './ns:AddtlNtryInf', transaction, 'name') ns, node, './ns:AddtlNtryInf', transaction, 'name')
if not transaction.get('name'):
transaction['name'] = '/'
if not transaction.get('ref'):
self.add_value_from_node( self.add_value_from_node(
ns, node, [ ns, node, [
'./ns:NtryDtls/ns:RmtInf/ns:Strd/ns:CdtrRefInf/ns:Ref',
'./ns:NtryDtls/ns:Btch/ns:PmtInfId', './ns:NtryDtls/ns:Btch/ns:PmtInfId',
'./ns:NtryDtls/ns:TxDtls/ns:Refs/ns:AcctSvcrRef'
], ],
transaction, 'ref' transaction, 'ref'
) )
transaction['data'] = etree.tostring(node)
return transaction
details_nodes = node.xpath(
'./ns:NtryDtls/ns:TxDtls', namespaces={'ns': ns})
if len(details_nodes) == 0:
yield transaction
return
transaction_base = transaction
for node in details_nodes:
transaction = transaction_base.copy()
self.parse_transaction_details(ns, node, transaction)
yield transaction
def get_balance_amounts(self, ns, node): def get_balance_amounts(self, ns, node):
"""Return opening and closing balance. """Return opening and closing balance.
@ -193,12 +202,15 @@ class CamtParser(models.AbstractModel):
ns, node, './ns:Acct/ns:Ccy', result, 'currency') ns, node, './ns:Acct/ns:Ccy', result, 'currency')
result['balance_start'], result['balance_end_real'] = ( result['balance_start'], result['balance_end_real'] = (
self.get_balance_amounts(ns, node)) self.get_balance_amounts(ns, node))
transaction_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns})
result['transactions'] = []
for entry_node in transaction_nodes:
transaction = self.parse_transaction(ns, entry_node)
if transaction:
result['transactions'].append(transaction)
entry_nodes = node.xpath('./ns:Ntry', namespaces={'ns': ns})
transactions = []
for entry_node in entry_nodes:
transactions.extend(self.parse_entry(ns, entry_node))
result['transactions'] = transactions
result['date'] = sorted(transactions,
key=lambda x: x['date'],
reverse=True
)[0]['date']
return result return result
def check_version(self, ns, root): def check_version(self, ns, root):

26
account_bank_statement_import_camt/test_files/golden-camt053-txdtls.pydata

@ -0,0 +1,26 @@
(None,
'CH1111000000123456789',
[{'balance_end_real': 79443.15,
'balance_start': 75960.15,
'date': '2017-03-22',
'name': '20170323123456789012345',
'transactions': [{'account_number': 'CH2222000000123456789',
'amount': 2187.0,
'data': '<TxDtls xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.04" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\n <Refs>\n <AcctSvcrRef>123456CHCAFEBABE</AcctSvcrRef>\n <Prtry>\n <Tp>01</Tp>\n <Ref>123456CHCAFEBABE</Ref>\n </Prtry>\n </Refs>\n <Amt Ccy="CHF">2187.00</Amt>\n <CdtDbtInd>CRDT</CdtDbtInd>\n <BkTxCd>\n <Domn>\n <Cd>PMNT</Cd>\n <Fmly>\n <Cd>RCDT</Cd>\n <SubFmlyCd>AUTT</SubFmlyCd>\n </Fmly>\n </Domn>\n </BkTxCd>\n <RltdPties>\n <Dbtr>\n <Nm>Banque Cantonale Vaudoise</Nm>\n <PstlAdr>\n <StrtNm>Place Saint-Fran&#231;ois</StrtNm>\n <BldgNb>14</BldgNb>\n <PstCd>1003</PstCd>\n <TwnNm>Lausanne</TwnNm>\n <Ctry>CH1</Ctry>\n </PstlAdr>\n </Dbtr>\n <DbtrAcct>\n <Id>\n <IBAN>CH2222000000123456789</IBAN>\n </Id>\n </DbtrAcct>\n </RltdPties>\n <RltdAgts>\n <DbtrAgt>\n <FinInstnId>\n <BICFI>POFICHBEXXX</BICFI>\n <Nm>POSTFINANCE AG</Nm>\n <PstlAdr>\n <AdrLine>MINGERSTRASSE 20</AdrLine>\n <AdrLine>3030 BERNE</AdrLine>\n </PstlAdr>\n </FinInstnId>\n </DbtrAgt>\n </RltdAgts>\n <RmtInf>\n <Strd>\n <CdtrRefInf>\n <Tp>\n <CdOrPrtry>\n <Prtry>ISR Reference</Prtry>\n </CdOrPrtry>\n </Tp>\n <Ref>302388292000011111111111111</Ref>\n </CdtrRefInf>\n <AddtlRmtInf>?REJECT?0</AddtlRmtInf>\n </Strd>\n </RmtInf>\n <RltdDts>\n <AccptncDtTm>2017-03-22T20:00:00</AccptncDtTm>\n </RltdDts>\n </TxDtls>\n ',
'date': '2017-03-22',
'execution_date': '2017-03-22',
'name': u'CR\xc9DIT GROUP\xc9 BVR TRAITEMENT DU 22.03.2017 NUM\xc9RO CLIENT 01-70884-3 PAQUET ID: 123456CHCAFEBABE',
'partner_country': 'CH1',
'partner_name': 'Banque Cantonale Vaudoise',
'ref': '302388292000011111111111111',
'value_date': '2017-03-23'},
{'account_number': 'CH3333000000123456789',
'amount': 1296.0,
'data': '<TxDtls xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.04" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">\n <Refs>\n <AcctSvcrRef>123456CHCAFEBABE</AcctSvcrRef>\n <Prtry>\n <Tp>01</Tp>\n <Ref>123456CHCAFEBABE</Ref>\n </Prtry>\n </Refs>\n <Amt Ccy="CHF">1296.00</Amt>\n <CdtDbtInd>CRDT</CdtDbtInd>\n <BkTxCd>\n <Domn>\n <Cd>PMNT</Cd>\n <Fmly>\n <Cd>RCDT</Cd>\n <SubFmlyCd>AUTT</SubFmlyCd>\n </Fmly>\n </Domn>\n </BkTxCd>\n <RltdPties>\n <Dbtr>\n <Nm>Banque Cantonale Vaudoise</Nm>\n <PstlAdr>\n <StrtNm>Place Saint-Fran&#231;ois</StrtNm>\n <BldgNb>14</BldgNb>\n <PstCd>1003</PstCd>\n <TwnNm>Lausanne</TwnNm>\n <Ctry>CH2</Ctry>\n </PstlAdr>\n </Dbtr>\n <DbtrAcct>\n <Id>\n <IBAN>CH3333000000123456789</IBAN>\n </Id>\n </DbtrAcct>\n </RltdPties>\n <RltdAgts>\n <DbtrAgt>\n <FinInstnId>\n <BICFI>POFICHBEYYY</BICFI>\n <Nm>POSTFINANCE AG</Nm>\n <PstlAdr>\n <AdrLine>MINGERSTRASSE 20</AdrLine>\n <AdrLine>3030 BERNE</AdrLine>\n </PstlAdr>\n </FinInstnId>\n </DbtrAgt>\n </RltdAgts>\n <RmtInf>\n <Strd>\n <CdtrRefInf>\n <Tp>\n <CdOrPrtry>\n <Prtry>ISR Reference</Prtry>\n </CdOrPrtry>\n </Tp>\n <Ref>302388292000022222222222222</Ref>\n </CdtrRefInf>\n <AddtlRmtInf>?REJECT?0</AddtlRmtInf>\n </Strd>\n </RmtInf>\n <RltdDts>\n <AccptncDtTm>2017-03-22T20:00:00</AccptncDtTm>\n </RltdDts>\n </TxDtls>\n ',
'date': '2017-03-22',
'execution_date': '2017-03-22',
'name': u'CR\xc9DIT GROUP\xc9 BVR TRAITEMENT DU 22.03.2017 NUM\xc9RO CLIENT 01-70884-3 PAQUET ID: 123456CHCAFEBABE',
'partner_country': 'CH2',
'partner_name': 'Banque Cantonale Vaudoise',
'ref': '302388292000022222222222222',
'value_date': '2017-03-23'}]}])

45
account_bank_statement_import_camt/test_files/golden-camt053.pydata

@ -0,0 +1,45 @@
(None,
'NL77ABNA0574908765',
[{'balance_end_real': 15121.12,
'balance_start': 15568.27,
'date': '2014-01-05',
'name': '1234Test/1',
'transactions': [{'account_bic': 'ABNANL2A',
'account_number': 'NL46ABNA0499998748',
'amount': -754.25,
'data': '<TxDtls xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">\n <Refs>\n <InstrId>INNDNL2U20141231000142300002844</InstrId>\n <EndToEndId>435005714488-ABNO33052620</EndToEndId>\n <MndtId>1880000341866</MndtId>\n </Refs>\n <AmtDtls>\n <TxAmt>\n <Amt Ccy="EUR">754.25</Amt>\n </TxAmt>\n </AmtDtls>\n <RltdPties>\n <Cdtr>\n <Nm>INSURANCE COMPANY TESTX</Nm>\n <PstlAdr>\n <StrtNm>TEST STREET 20</StrtNm>\n <TwnNm>1234 AB TESTCITY</TwnNm>\n <Ctry>NL</Ctry>\n </PstlAdr>\n </Cdtr>\n <CdtrAcct>\n <Id>\n <IBAN>NL46ABNA0499998748</IBAN>\n </Id>\n </CdtrAcct>\n </RltdPties>\n <RltdAgts>\n <CdtrAgt>\n <FinInstnId>\n <BIC>ABNANL2A</BIC>\n </FinInstnId>\n </CdtrAgt>\n </RltdAgts>\n <RmtInf>\n <Ustrd>Insurance policy 857239PERIOD 01.01.2014 - 31.12.2014</Ustrd>\n </RmtInf>\n <AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2014 - 31.12.2014</AddtlTxInf>\n </TxDtls>\n ',
'date': '2014-01-05',
'execution_date': '2014-01-05',
'name': 'MKB Insurance 859239PERIOD 01.01.2014 - 31.12.2014',
'note': 'Insurance policy 857239PERIOD 01.01.2014 - 31.12.2014',
'partner_country': 'NL',
'partner_name': 'INSURANCE COMPANY TESTX',
'ref': '435005714488-ABNO33052620',
'transfer_type': 'EI',
'value_date': '2014-01-05'},
{'account_bic': 'ABNANL2A',
'account_number': 'NL46ABNA0499998748',
'amount': -594.05,
'data': '<TxDtls xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">\n <Refs>\n <InstrId>TESTBANK/NL/20141229/01206408</InstrId>\n <EndToEndId>TESTBANK/NL/20141229/01206408</EndToEndId>\n <MndtId>NL22ZZZ524885430000-C0125.1</MndtId>\n </Refs>\n <AmtDtls>\n <TxAmt>\n <Amt Ccy="EUR">564.05</Amt>\n </TxAmt>\n </AmtDtls>\n <RltdPties>\n <Cdtr>\n <Nm>Test Customer</Nm>\n <PstlAdr>\n <Ctry>NL</Ctry>\n </PstlAdr>\n </Cdtr>\n <CdtrAcct>\n <Id>\n <IBAN>NL46ABNA0499998748</IBAN>\n </Id>\n </CdtrAcct>\n </RltdPties>\n <RltdAgts>\n <CdtrAgt>\n <FinInstnId>\n <BIC>ABNANL2A</BIC>\n </FinInstnId>\n </CdtrAgt>\n </RltdAgts>\n <RmtInf>\n <Ustrd>Direct Debit S14 0410</Ustrd>\n </RmtInf>\n <RtrInf>\n <Rsn>\n <Cd>AC06</Cd>\n </Rsn>\n </RtrInf>\n <AddtlTxInf>Direct debit S14 0410 AC07 Rek.nummer blokkade TESTBANK/NL/20141229/01206408</AddtlTxInf>\n </TxDtls>\n ',
'date': '2014-01-05',
'execution_date': '2014-01-05',
'name': 'Direct debit S14 0410 AC07 Rek.nummer blokkade TESTBANK/NL/20141229/01206408',
'note': 'Direct Debit S14 0410',
'partner_country': 'NL',
'partner_name': 'Test Customer',
'ref': 'TESTBANK/NL/20141229/01206408',
'transfer_type': 'EIST',
'value_date': '2014-01-05'},
{'account_bic': 'ABNANL2A',
'account_number': 'NL69ABNA0522123643',
'amount': 1405.31,
'data': '<TxDtls xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.02">\n <Refs>\n <InstrId>INNDNL2U20140105000217200000708</InstrId>\n <EndToEndId>115</EndToEndId>\n </Refs>\n <AmtDtls>\n <TxAmt>\n <Amt Ccy="EUR">1405.31</Amt>\n </TxAmt>\n </AmtDtls>\n <RltdPties>\n <Dbtr>\n <Nm>3rd party Media</Nm>\n <PstlAdr>\n <StrtNm>SOMESTREET 570-A</StrtNm>\n <TwnNm>1276 ML HOUSCITY</TwnNm>\n <Ctry>NL</Ctry>\n </PstlAdr>\n </Dbtr>\n <DbtrAcct>\n <Id>\n <IBAN>NL69ABNA0522123643</IBAN>\n </Id>\n </DbtrAcct>\n </RltdPties>\n <RltdAgts>\n <DbtrAgt>\n <FinInstnId>\n <BIC>ABNANL2A</BIC>\n </FinInstnId>\n </DbtrAgt>\n </RltdAgts>\n <AddtlTxInf>#RD PARTY MEDIA CUSNO 90782 4210773</AddtlTxInf>\n </TxDtls>\n ',
'date': '2014-01-05',
'execution_date': '2014-01-05',
'name': '#RD PARTY MEDIA CUSNO 90782 4210773',
'note': 'INNDNL2U20140105000217200000708',
'partner_country': 'NL',
'partner_name': '3rd party Media',
'ref': '115',
'transfer_type': 'ET',
'value_date': '2014-01-05'}]}])

214
account_bank_statement_import_camt/test_files/test-camt053-txdtls

@ -0,0 +1,214 @@
<?xml version="1.0" encoding="UTF-8"?>
<Document xmlns="urn:iso:std:iso:20022:tech:xsd:camt.053.001.04" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:camt.053.001.04 camt.053.001.04.xsd">
<BkToCstmrStmt>
<GrpHdr>
<MsgId>20170323312345678900000</MsgId>
<CreDtTm>2017-03-23T14:47:00</CreDtTm>
<MsgPgntn>
<PgNb>1</PgNb>
<LastPgInd>true</LastPgInd>
</MsgPgntn>
<AddtlInf>Test</AddtlInf>
</GrpHdr>
<Stmt>
<Id>20170323123456789012345</Id>
<ElctrncSeqNb>58</ElctrncSeqNb>
<CreDtTm>2017-03-23T14:47:00</CreDtTm>
<FrToDt>
<FrDtTm>2017-03-23T00:00:00</FrDtTm>
<ToDtTm>2017-03-23T23:59:59</ToDtTm>
</FrToDt>
<Acct>
<Id>
<IBAN>CH1111000000123456789</IBAN>
</Id>
<Ownr>
<Nm>Open Net S. à r.l. Prilly</Nm>
</Ownr>
</Acct>
<Bal>
<Tp>
<CdOrPrtry>
<Cd>OPBD</Cd>
</CdOrPrtry>
</Tp>
<Amt Ccy="CHF">75960.15</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2017-03-22</Dt>
</Dt>
</Bal>
<Bal>
<Tp>
<CdOrPrtry>
<Cd>CLBD</Cd>
</CdOrPrtry>
</Tp>
<Amt Ccy="CHF">79443.15</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2017-03-23</Dt>
</Dt>
</Bal>
<Ntry>
<NtryRef>012345678</NtryRef>
<Amt Ccy="CHF">3483.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<RvslInd>false</RvslInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2017-03-22</Dt>
</BookgDt>
<ValDt>
<Dt>2017-03-23</Dt>
</ValDt>
<AcctSvcrRef>20170323001234567891234567891234</AcctSvcrRef>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>VCOM</SubFmlyCd>
</Fmly>
</Domn>
</BkTxCd>
<NtryDtls>
<Btch>
<NbOfTxs>2</NbOfTxs>
</Btch>
<TxDtls>
<Refs>
<AcctSvcrRef>123456CHCAFEBABE</AcctSvcrRef>
<Prtry>
<Tp>01</Tp>
<Ref>123456CHCAFEBABE</Ref>
</Prtry>
</Refs>
<Amt Ccy="CHF">2187.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>AUTT</SubFmlyCd>
</Fmly>
</Domn>
</BkTxCd>
<RltdPties>
<Dbtr>
<Nm>Banque Cantonale Vaudoise</Nm>
<PstlAdr>
<StrtNm>Place Saint-François</StrtNm>
<BldgNb>14</BldgNb>
<PstCd>1003</PstCd>
<TwnNm>Lausanne</TwnNm>
<Ctry>CH1</Ctry>
</PstlAdr>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>CH2222000000123456789</IBAN>
</Id>
</DbtrAcct>
</RltdPties>
<RltdAgts>
<DbtrAgt>
<FinInstnId>
<BICFI>POFICHBEXXX</BICFI>
<Nm>POSTFINANCE AG</Nm>
<PstlAdr>
<AdrLine>MINGERSTRASSE 20</AdrLine>
<AdrLine>3030 BERNE</AdrLine>
</PstlAdr>
</FinInstnId>
</DbtrAgt>
</RltdAgts>
<RmtInf>
<Strd>
<CdtrRefInf>
<Tp>
<CdOrPrtry>
<Prtry>ISR Reference</Prtry>
</CdOrPrtry>
</Tp>
<Ref>302388292000011111111111111</Ref>
</CdtrRefInf>
<AddtlRmtInf>?REJECT?0</AddtlRmtInf>
</Strd>
</RmtInf>
<RltdDts>
<AccptncDtTm>2017-03-22T20:00:00</AccptncDtTm>
</RltdDts>
</TxDtls>
<TxDtls>
<Refs>
<AcctSvcrRef>123456CHCAFEBABE</AcctSvcrRef>
<Prtry>
<Tp>01</Tp>
<Ref>123456CHCAFEBABE</Ref>
</Prtry>
</Refs>
<Amt Ccy="CHF">1296.00</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<BkTxCd>
<Domn>
<Cd>PMNT</Cd>
<Fmly>
<Cd>RCDT</Cd>
<SubFmlyCd>AUTT</SubFmlyCd>
</Fmly>
</Domn>
</BkTxCd>
<RltdPties>
<Dbtr>
<Nm>Banque Cantonale Vaudoise</Nm>
<PstlAdr>
<StrtNm>Place Saint-François</StrtNm>
<BldgNb>14</BldgNb>
<PstCd>1003</PstCd>
<TwnNm>Lausanne</TwnNm>
<Ctry>CH2</Ctry>
</PstlAdr>
</Dbtr>
<DbtrAcct>
<Id>
<IBAN>CH3333000000123456789</IBAN>
</Id>
</DbtrAcct>
</RltdPties>
<RltdAgts>
<DbtrAgt>
<FinInstnId>
<BICFI>POFICHBEYYY</BICFI>
<Nm>POSTFINANCE AG</Nm>
<PstlAdr>
<AdrLine>MINGERSTRASSE 20</AdrLine>
<AdrLine>3030 BERNE</AdrLine>
</PstlAdr>
</FinInstnId>
</DbtrAgt>
</RltdAgts>
<RmtInf>
<Strd>
<CdtrRefInf>
<Tp>
<CdOrPrtry>
<Prtry>ISR Reference</Prtry>
</CdOrPrtry>
</Tp>
<Ref>302388292000022222222222222</Ref>
</CdtrRefInf>
<AddtlRmtInf>?REJECT?0</AddtlRmtInf>
</Strd>
</RmtInf>
<RltdDts>
<AccptncDtTm>2017-03-22T20:00:00</AccptncDtTm>
</RltdDts>
</TxDtls>
</NtryDtls>
<AddtlNtryInf>CRÉDIT GROUPÉ BVR TRAITEMENT DU 22.03.2017 NUMÉRO CLIENT 01-70884-3 PAQUET ID: 123456CHCAFEBABE</AddtlNtryInf>
</Ntry>
</Stmt>
</BkToCstmrStmt>
</Document>

45
account_bank_statement_import_camt/tests/test_import_bank_statement.py

@ -1,12 +1,53 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
"""Run test to import camt.053 import.""" """Run test to import camt.053 import."""
# © 2013-2016 Therp BV <http://therp.nl> # © 2013-2016 Therp BV <http://therp.nl>
# Copyright 2017 Open Net Sàrl
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html). # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
import base64 import base64
import difflib
import pprint
import tempfile
from odoo.tests.common import TransactionCase from odoo.tests.common import TransactionCase
from odoo.tools.misc import file_open from odoo.tools.misc import file_open
DATA_DIR = 'account_bank_statement_import_camt/test_files/'
class TestParser(TransactionCase):
"""Tests for the camt parser itself."""
def setUp(self):
super(TestParser, self).setUp()
self.parser = self.env['account.bank.statement.import.camt.parser']
def _do_parse_test(self, inputfile, goldenfile):
with file_open(inputfile) as testfile:
data = testfile.read()
res = self.parser.parse(data)
with tempfile.NamedTemporaryFile(suffix='.pydata') as temp:
pprint.pprint(res, temp)
with file_open(goldenfile) as golden:
temp.seek(0)
diff = list(
difflib.unified_diff(golden.readlines(), temp.readlines(),
golden.name, temp.name))
if len(diff) > 2:
self.fail(
"actual output doesn't match exptected output:\n%s" %
"".join(diff))
def test_parse(self):
self._do_parse_test(
DATA_DIR + 'test-camt053',
DATA_DIR + 'golden-camt053.pydata')
def test_parse_txdtls(self):
self._do_parse_test(
DATA_DIR + 'test-camt053-txdtls',
DATA_DIR + 'golden-camt053-txdtls.pydata')
class TestImport(TransactionCase): class TestImport(TransactionCase):
"""Run test to import camt import.""" """Run test to import camt import."""
transactions = [ transactions = [
@ -36,9 +77,7 @@ class TestImport(TransactionCase):
def test_statement_import(self): def test_statement_import(self):
"""Test correct creation of single statement.""" """Test correct creation of single statement."""
action = {} action = {}
with file_open(
'account_bank_statement_import_camt/test_files/test-camt053'
) as testfile:
with file_open(DATA_DIR + 'test-camt053') as testfile:
action = self.env['account.bank.statement.import'].create({ action = self.env['account.bank.statement.import'].create({
'data_file': base64.b64encode(testfile.read()), 'data_file': base64.b64encode(testfile.read()),
}).import_file() }).import_file()

Loading…
Cancel
Save