Browse Source

[ENH] Support zip files.

pull/36/head
Ronald Portier (Therp BV) 10 years ago
parent
commit
26fac7bfa7
  1. 33
      account_bank_statement_import/models/account_bank_statement_import.py
  2. 30
      account_bank_statement_import_camt/test_files/test-camt053.xml
  3. BIN
      account_bank_statement_import_camt/test_files/test-camt053.zip
  4. 11
      account_bank_statement_import_camt/tests/test_import_bank_statement.py
  5. 2
      account_bank_statement_import_mt940_base/mt940.py
  6. BIN
      bank_statement_parse_camt/test_files/test-camt053.zip

33
account_bank_statement_import/models/account_bank_statement_import.py

@ -2,6 +2,8 @@
"""Framework for importing bank statement files.""" """Framework for importing bank statement files."""
import logging import logging
import base64 import base64
from StringIO import StringIO
from zipfile import ZipFile, BadZipfile # BadZipFile in Python >= 3.2
from openerp import api, models, fields from openerp import api, models, fields
from openerp.tools.translate import _ from openerp.tools.translate import _
@ -52,7 +54,7 @@ class AccountBankStatementImport(models.TransientModel):
@api.multi @api.multi
def import_file(self): def import_file(self):
""" Process the file chosen in the wizard, create bank statement(s) and
"""Process the file chosen in the wizard, create bank statement(s) and
go to reconciliation.""" go to reconciliation."""
self.ensure_one() self.ensure_one()
data_file = base64.b64decode(self.data_file) data_file = base64.b64decode(self.data_file)
@ -71,13 +73,38 @@ class AccountBankStatementImport(models.TransientModel):
'type': 'ir.actions.client', 'type': 'ir.actions.client',
} }
@api.model
def _parse_all_files(self, data_file):
"""Parse one file or multiple files from zip-file.
Return array of statements for further processing.
"""
statements = []
files = [data_file]
try:
with ZipFile(StringIO(data_file), 'r') as archive:
files = [
archive.read(filename) for filename in archive.namelist()
if not filename.endswith('/')
]
except BadZipfile:
pass
# Parse the file(s)
for import_file in files:
# The appropriate implementation module(s) returns the statements.
# Actually we don't care wether all the files have the same
# format. Although unlikely you might mix mt940 and camt files
# in one zipfile.
statements += self._parse_file(import_file)
return statements
@api.model @api.model
def _import_file(self, data_file): def _import_file(self, data_file):
""" Create bank statement(s) from file.""" """ Create bank statement(s) from file."""
# The appropriate implementation module returns the required data # The appropriate implementation module returns the required data
statement_ids = [] statement_ids = []
notifications = [] notifications = []
parse_result = self._parse_file(data_file)
parse_result = self._parse_all_files(data_file)
# Check for old version result, with separate currency and account # Check for old version result, with separate currency and account
if isinstance(parse_result, tuple) and len(parse_result) == 3: if isinstance(parse_result, tuple) and len(parse_result) == 3:
(currency_code, account_number, statements) = parse_result (currency_code, account_number, statements) = parse_result
@ -125,7 +152,7 @@ class AccountBankStatementImport(models.TransientModel):
return self._create_bank_statement(stmt_vals) return self._create_bank_statement(stmt_vals)
@api.model @api.model
def _parse_file(self, data_file):
def _parse_file(self, dummy_data_file):
""" Each module adding a file support must extends this method. It """ Each module adding a file support must extends this method. It
processes the file if it can, returns super otherwise, resulting in a processes the file if it can, returns super otherwise, resulting in a
chain of responsability. chain of responsability.

30
account_bank_statement_import_camt/test_files/test-camt053.xml

@ -2,15 +2,15 @@
<BkToCstmrStmt> <BkToCstmrStmt>
<GrpHdr> <GrpHdr>
<MsgId>TESTBANK/NL/1420561226673</MsgId> <MsgId>TESTBANK/NL/1420561226673</MsgId>
<CreDtTm>2013-01-06T16:20:26.673Z</CreDtTm>
<CreDtTm>2014-01-06T16:20:26.673Z</CreDtTm>
</GrpHdr> </GrpHdr>
<Stmt> <Stmt>
<Id>1234Test/1</Id> <Id>1234Test/1</Id>
<LglSeqNb>2</LglSeqNb> <LglSeqNb>2</LglSeqNb>
<CreDtTm>2013-01-06T16:20:26.673Z</CreDtTm>
<CreDtTm>2014-01-06T16:20:26.673Z</CreDtTm>
<FrToDt> <FrToDt>
<FrDtTm>2013-01-05T00:00:00.000Z</FrDtTm>
<ToDtTm>2013-01-05T23:59:59.999Z</ToDtTm>
<FrDtTm>2014-01-05T00:00:00.000Z</FrDtTm>
<ToDtTm>2014-01-05T23:59:59.999Z</ToDtTm>
</FrToDt> </FrToDt>
<Acct> <Acct>
<Id> <Id>
@ -32,7 +32,7 @@
<Amt Ccy="EUR">15568.27</Amt> <Amt Ccy="EUR">15568.27</Amt>
<CdtDbtInd>CRDT</CdtDbtInd> <CdtDbtInd>CRDT</CdtDbtInd>
<Dt> <Dt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</Dt> </Dt>
</Bal> </Bal>
<Bal> <Bal>
@ -44,7 +44,7 @@
<Amt Ccy="EUR">15121.12</Amt> <Amt Ccy="EUR">15121.12</Amt>
<CdtDbtInd>CRDT</CdtDbtInd> <CdtDbtInd>CRDT</CdtDbtInd>
<Dt> <Dt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</Dt> </Dt>
</Bal> </Bal>
<Ntry> <Ntry>
@ -52,10 +52,10 @@
<CdtDbtInd>DBIT</CdtDbtInd> <CdtDbtInd>DBIT</CdtDbtInd>
<Sts>BOOK</Sts> <Sts>BOOK</Sts>
<BookgDt> <BookgDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</BookgDt> </BookgDt>
<ValDt> <ValDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</ValDt> </ValDt>
<BkTxCd> <BkTxCd>
<Domn> <Domn>
@ -104,9 +104,9 @@
</CdtrAgt> </CdtrAgt>
</RltdAgts> </RltdAgts>
<RmtInf> <RmtInf>
<Ustrd>Insurance policy 857239PERIOD 01.01.2013 - 31.12.2013</Ustrd>
<Ustrd>Insurance policy 857239PERIOD 01.01.2014 - 31.12.2014</Ustrd>
</RmtInf> </RmtInf>
<AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2013 - 31.12.2013</AddtlTxInf>
<AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2014 - 31.12.2014</AddtlTxInf>
</TxDtls> </TxDtls>
</NtryDtls> </NtryDtls>
</Ntry> </Ntry>
@ -116,10 +116,10 @@
<RvslInd>true</RvslInd> <RvslInd>true</RvslInd>
<Sts>BOOK</Sts> <Sts>BOOK</Sts>
<BookgDt> <BookgDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</BookgDt> </BookgDt>
<ValDt> <ValDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</ValDt> </ValDt>
<BkTxCd> <BkTxCd>
<Domn> <Domn>
@ -182,10 +182,10 @@
<CdtDbtInd>CRDT</CdtDbtInd> <CdtDbtInd>CRDT</CdtDbtInd>
<Sts>BOOK</Sts> <Sts>BOOK</Sts>
<BookgDt> <BookgDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</BookgDt> </BookgDt>
<ValDt> <ValDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</ValDt> </ValDt>
<BkTxCd> <BkTxCd>
<Domn> <Domn>
@ -202,7 +202,7 @@
<NtryDtls> <NtryDtls>
<TxDtls> <TxDtls>
<Refs> <Refs>
<InstrId>INNDNL2U20130105000217200000708</InstrId>
<InstrId>INNDNL2U20140105000217200000708</InstrId>
<EndToEndId>115</EndToEndId> <EndToEndId>115</EndToEndId>
</Refs> </Refs>
<AmtDtls> <AmtDtls>

BIN
account_bank_statement_import_camt/test_files/test-camt053.zip

11
account_bank_statement_import_camt/tests/test_import_bank_statement.py

@ -31,11 +31,10 @@ class TestImport(TestStatementFile):
{ {
'remote_account': 'NL46ABNA0499998748', 'remote_account': 'NL46ABNA0499998748',
'transferred_amount': -754.25, 'transferred_amount': -754.25,
'value_date': '2013-01-05',
'value_date': '2014-01-05',
'ref': '435005714488-ABNO33052620', 'ref': '435005714488-ABNO33052620',
}, },
] ]
# statement name is account number + '-' + date of last 62F line:
self._test_statement_import( self._test_statement_import(
'account_bank_statement_import_camt', 'test-camt053.xml', 'account_bank_statement_import_camt', 'test-camt053.xml',
'1234Test/1', '1234Test/1',
@ -43,3 +42,11 @@ class TestImport(TestStatementFile):
start_balance=15568.27, end_balance=15121.12, start_balance=15568.27, end_balance=15121.12,
transactions=transactions transactions=transactions
) )
def test_zip_import(self):
"""Test import of multiple statements from zip file."""
self._test_statement_import(
'account_bank_statement_import_camt', 'test-camt053.zip',
'1234Test/2', # Only name of first statement
local_account='NL77ABNA0574908765',
)

2
account_bank_statement_import_mt940_base/mt940.py

@ -111,7 +111,7 @@ class MT940(object):
This in fact uses the ING syntax, override in others.""" This in fact uses the ING syntax, override in others."""
self.mt940_type = 'General' self.mt940_type = 'General'
self.header_lines = 3 # Number of lines to skip self.header_lines = 3 # Number of lines to skip
self.header_regex = '^0000 01INGBNL2AXXXX|^{1'
self.header_regex = '^0000 01INGBNL2AXXXX|^{1' # Start of header
self.footer_regex = '^-}$|^-XXX$' # Stop processing on seeing this self.footer_regex = '^-}$|^-XXX$' # Stop processing on seeing this
self.tag_regex = '^:[0-9]{2}[A-Z]*:' # Start of new tag self.tag_regex = '^:[0-9]{2}[A-Z]*:' # Start of new tag
self.current_statement = None self.current_statement = None

BIN
bank_statement_parse_camt/test_files/test-camt053.zip

Loading…
Cancel
Save