Browse Source

Merge pull request #36 from NL66278/8.0_import_parsers_complete_therp

[ADD] support zip files
pull/50/head
Holger Brunn 9 years ago
parent
commit
6606d0b2b1
  1. 1
      account_bank_statement_import/__init__.py
  2. 7
      account_bank_statement_import/__openerp__.py
  3. 2
      account_bank_statement_import/models/__init__.py
  4. 84
      account_bank_statement_import/models/account_bank_statement_import.py
  5. 2
      account_bank_statement_import/parserlib.py
  6. 6
      account_bank_statement_import/tests/test_import_bank_statement.py
  7. 2
      account_bank_statement_import_camt/__openerp__.py
  8. 30
      account_bank_statement_import_camt/test_files/test-camt053.xml
  9. BIN
      account_bank_statement_import_camt/test_files/test-camt053.zip
  10. 11
      account_bank_statement_import_camt/tests/test_import_bank_statement.py
  11. 1
      account_bank_statement_import_mt940_base/__init__.py
  12. 4
      account_bank_statement_import_mt940_base/__openerp__.py
  13. 2
      account_bank_statement_import_mt940_base/mt940.py
  14. 2
      account_bank_statement_import_mt940_nl_ing/README.rst
  15. 1
      account_bank_statement_import_mt940_nl_ing/__init__.py
  16. 4
      account_bank_statement_import_mt940_nl_ing/__openerp__.py
  17. 4
      account_bank_statement_import_mt940_nl_ing/tests/__init__.py
  18. 2
      account_bank_statement_import_mt940_nl_rabo/__init__.py
  19. 3
      account_bank_statement_import_mt940_nl_rabo/__openerp__.py
  20. 5
      account_bank_statement_import_ofx/__openerp__.py
  21. 8
      account_bank_statement_import_ofx/account_bank_statement_import_ofx.py
  22. 4
      account_bank_statement_import_qif/__openerp__.py
  23. 10
      account_bank_statement_import_qif/account_bank_statement_import_qif.py
  24. 36
      account_bank_statement_import_save_file/__openerp__.py
  25. 31
      base_bank_account_number_unique/README.rst
  26. 22
      base_bank_account_number_unique/__openerp__.py
  27. 7
      base_bank_account_number_unique/hooks.py
  28. 4
      base_bank_account_number_unique/tests/test_base_bank_account_number_unique.py

1
account_bank_statement_import/__init__.py

@ -1 +1,2 @@
# -*- coding: utf-8 -*-
from . import models

7
account_bank_statement_import/__openerp__.py

@ -1,14 +1,15 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
{
'name': 'Account Bank Statement Import',
'category': 'Banking addons',
'version': '8.0.1.0.1',
'version': '8.0.1.0.2',
'license': 'AGPL-3',
'author': 'OpenERP SA,'
'Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/bank-statement-import',
'depends': ['account'],
'data': [
"views/account_config_settings.xml",
'views/account_config_settings.xml',
'views/account_bank_statement_import_view.xml',
],
'demo': [

2
account_bank_statement_import/models/__init__.py

@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
from . import res_partner_bank
from . import account_bank_statement_import

84
account_bank_statement_import/models/account_bank_statement_import.py

@ -2,16 +2,19 @@
"""Framework for importing bank statement files."""
import logging
import base64
from StringIO import StringIO
from zipfile import ZipFile, BadZipfile # BadZipFile in Python >= 3.2
from openerp import api, models, fields
from openerp.tools.translate import _
from openerp.exceptions import Warning
from openerp.exceptions import Warning as UserError
_logger = logging.getLogger(__name__)
_logger = logging.getLogger(__name__) # pylint: disable=invalid-name
class AccountBankStatementLine(models.Model):
"""Extend model account.bank.statement.line."""
# pylint: disable=too-many-public-methods
_inherit = "account.bank.statement.line"
# Ensure transactions can be imported only once (if the import format
@ -35,6 +38,7 @@ class AccountBankStatementImport(models.TransientModel):
""" Return False if the journal_id can't be provided by the parsed
file and must be provided by the wizard.
See account_bank_statement_import_qif """
# pylint: disable=no-self-use
return True
journal_id = fields.Many2one(
@ -52,12 +56,14 @@ class AccountBankStatementImport(models.TransientModel):
@api.multi
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."""
self.ensure_one()
data_file = base64.b64decode(self.data_file)
# pylint: disable=protected-access
statement_ids, notifications = self.with_context(
active_id=self.id)._import_file(data_file)
active_id=self.id # pylint: disable=no-member
)._import_file(data_file)
# dispatch to reconciliation interface
action = self.env.ref(
'account.action_bank_reconcile_bank_statements')
@ -71,21 +77,47 @@ class AccountBankStatementImport(models.TransientModel):
'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.
parse_result = self._parse_file(import_file)
# Check for old version result, with separate currency and account
if isinstance(parse_result, tuple) and len(parse_result) == 3:
(currency_code, account_number, new_statements) = parse_result
for stmt_vals in new_statements:
stmt_vals['currency_code'] = currency_code
stmt_vals['account_number'] = account_number
else:
new_statements = parse_result
statements += new_statements
return statements
@api.model
def _import_file(self, data_file):
""" Create bank statement(s) from file."""
# The appropriate implementation module returns the required data
statement_ids = []
notifications = []
parse_result = self._parse_file(data_file)
# Check for old version result, with separate currency and account
if isinstance(parse_result, tuple) and len(parse_result) == 3:
(currency_code, account_number, statements) = parse_result
for stmt_vals in statements:
stmt_vals['currency_code'] = currency_code
stmt_vals['account_number'] = account_number
else:
statements = parse_result
statements = self._parse_all_files(data_file)
# Check raw data:
self._check_parsed_data(statements)
# Import all statements:
@ -96,7 +128,7 @@ class AccountBankStatementImport(models.TransientModel):
statement_ids.append(statement_id)
notifications.extend(new_notifications)
if len(statement_ids) == 0:
raise Warning(_('You have already imported that file.'))
raise UserError(_('You have already imported that file.'))
return statement_ids, notifications
@api.model
@ -111,13 +143,14 @@ class AccountBankStatementImport(models.TransientModel):
currency_id = self._find_currency_id(currency_code)
bank_account_id = self._find_bank_account_id(account_number)
if not bank_account_id and account_number:
raise Warning(_('Can not find the account number %s.') %
account_number)
raise UserError(
_('Can not find the account number %s.') % account_number
)
# Find the bank journal
journal_id = self._get_journal(currency_id, bank_account_id)
# By now journal and account_number must be known
if not journal_id:
raise Warning(_('Can not determine journal for import.'))
raise UserError(_('Can not determine journal for import.'))
# Prepare statement data to be used for bank statements creation
stmt_vals = self._complete_statement(
stmt_vals, journal_id, account_number)
@ -126,6 +159,8 @@ class AccountBankStatementImport(models.TransientModel):
@api.model
def _parse_file(self, data_file):
# pylint: disable=no-self-use
# pylint: disable=unused-argument
""" Each module adding a file support must extends this method. It
processes the file if it can, returns super otherwise, resulting in a
chain of responsability.
@ -155,21 +190,22 @@ class AccountBankStatementImport(models.TransientModel):
-o 'partner_name': string
-o 'ref': string
"""
raise Warning(_(
raise UserError(_(
'Could not make sense of the given file.\n'
'Did you install the module to support this type of file?'
))
@api.model
def _check_parsed_data(self, statements):
# pylint: disable=no-self-use
""" Basic and structural verifications """
if len(statements) == 0:
raise Warning(_('This file doesn\'t contain any statement.'))
raise UserError(_('This file doesn\'t contain any statement.'))
for stmt_vals in statements:
if 'transactions' in stmt_vals and stmt_vals['transactions']:
return
# If we get here, no transaction was found:
raise Warning(_('This file doesn\'t contain any transaction.'))
raise UserError(_('This file doesn\'t contain any transaction.'))
@api.model
def _find_currency_id(self, currency_code):
@ -180,7 +216,7 @@ class AccountBankStatementImport(models.TransientModel):
if currency_ids:
return currency_ids[0].id
else:
raise Warning(_(
raise UserError(_(
'Statement has invalid currency code %s') % currency_code)
# if no currency_code is provided, we'll use the company currency
return self.env.user.company_id.currency_id.id
@ -207,7 +243,7 @@ class AccountBankStatementImport(models.TransientModel):
if journal_id:
if (bank_account.journal_id.id and
bank_account.journal_id.id != journal_id):
raise Warning(
raise UserError(
_('The account of this statement is linked to '
'another journal.'))
if not bank_account.journal_id.id:
@ -230,7 +266,7 @@ class AccountBankStatementImport(models.TransientModel):
currency_id,
journal_currency_id
)
raise Warning(_(
raise UserError(_(
'The currency of the bank statement is not '
'the same as the currency of the journal !'
))
@ -244,7 +280,7 @@ class AccountBankStatementImport(models.TransientModel):
currency_id,
company_currency_id
)
raise Warning(_(
raise UserError(_(
'The currency of the bank statement is not '
'the same as the company currency !'
))

2
account_bank_statement_import/parserlib.py

@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
"""Classes and definitions used in parsing bank statements."""
##############################################################################
#

6
account_bank_statement_import/tests/test_import_bank_statement.py

@ -23,7 +23,7 @@
#
##############################################################################
from openerp.tests.common import TransactionCase
from openerp.exceptions import Warning
from openerp.exceptions import Warning as UserError
class TestAccountBankStatementImport(TransactionCase):
@ -68,12 +68,12 @@ class TestAccountBankStatementImport(TransactionCase):
stmt_vals = {
'currency_code': 'EUR',
'account_number': '123456789'}
with self.assertRaises(Warning) as e:
with self.assertRaises(UserError) as e:
self.statement_import_model._import_statement(stmt_vals.copy())
self.assertEqual(e.exception.message,
'Can not find the account number 123456789.')
self.statement_import_model._create_bank_account('123456789')
with self.assertRaises(Warning) as e:
with self.assertRaises(UserError) as e:
self.statement_import_model._import_statement(stmt_vals.copy())
self.assertEqual(e.exception.message,
'Can not determine journal for import.')

2
account_bank_statement_import_camt/__openerp__.py

@ -19,7 +19,7 @@
##############################################################################
{
'name': 'CAMT Format Bank Statements Import',
'version': '8.0.0.3.0',
'version': '8.0.0.4.0',
'license': 'AGPL-3',
'author': 'Odoo Community Association (OCA), Therp BV',
'website': 'https://github.com/OCA/bank-statement-import',

30
account_bank_statement_import_camt/test_files/test-camt053.xml

@ -2,15 +2,15 @@
<BkToCstmrStmt>
<GrpHdr>
<MsgId>TESTBANK/NL/1420561226673</MsgId>
<CreDtTm>2013-01-06T16:20:26.673Z</CreDtTm>
<CreDtTm>2014-01-06T16:20:26.673Z</CreDtTm>
</GrpHdr>
<Stmt>
<Id>1234Test/1</Id>
<LglSeqNb>2</LglSeqNb>
<CreDtTm>2013-01-06T16:20:26.673Z</CreDtTm>
<CreDtTm>2014-01-06T16:20:26.673Z</CreDtTm>
<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>
<Acct>
<Id>
@ -32,7 +32,7 @@
<Amt Ccy="EUR">15568.27</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</Dt>
</Bal>
<Bal>
@ -44,7 +44,7 @@
<Amt Ccy="EUR">15121.12</Amt>
<CdtDbtInd>CRDT</CdtDbtInd>
<Dt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</Dt>
</Bal>
<Ntry>
@ -52,10 +52,10 @@
<CdtDbtInd>DBIT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</BookgDt>
<ValDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</ValDt>
<BkTxCd>
<Domn>
@ -104,9 +104,9 @@
</CdtrAgt>
</RltdAgts>
<RmtInf>
<Ustrd>Insurance policy 857239PERIOD 01.01.2013 - 31.12.2013</Ustrd>
<Ustrd>Insurance policy 857239PERIOD 01.01.2014 - 31.12.2014</Ustrd>
</RmtInf>
<AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2013 - 31.12.2013</AddtlTxInf>
<AddtlTxInf>MKB Insurance 859239PERIOD 01.01.2014 - 31.12.2014</AddtlTxInf>
</TxDtls>
</NtryDtls>
</Ntry>
@ -116,10 +116,10 @@
<RvslInd>true</RvslInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</BookgDt>
<ValDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</ValDt>
<BkTxCd>
<Domn>
@ -182,10 +182,10 @@
<CdtDbtInd>CRDT</CdtDbtInd>
<Sts>BOOK</Sts>
<BookgDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</BookgDt>
<ValDt>
<Dt>2013-01-05</Dt>
<Dt>2014-01-05</Dt>
</ValDt>
<BkTxCd>
<Domn>
@ -202,7 +202,7 @@
<NtryDtls>
<TxDtls>
<Refs>
<InstrId>INNDNL2U20130105000217200000708</InstrId>
<InstrId>INNDNL2U20140105000217200000708</InstrId>
<EndToEndId>115</EndToEndId>
</Refs>
<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',
'transferred_amount': -754.25,
'value_date': '2013-01-05',
'value_date': '2014-01-05',
'ref': '435005714488-ABNO33052620',
},
]
# statement name is account number + '-' + date of last 62F line:
self._test_statement_import(
'account_bank_statement_import_camt', 'test-camt053.xml',
'1234Test/1',
@ -43,3 +42,11 @@ class TestImport(TestStatementFile):
start_balance=15568.27, end_balance=15121.12,
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',
)

1
account_bank_statement_import_mt940_base/__init__.py

@ -1 +1,2 @@
# -*- coding: utf-8 -*-
from . import mt940

4
account_bank_statement_import_mt940_base/__openerp__.py

@ -19,7 +19,7 @@
##############################################################################
{
'name': 'MT940 Bank Statements Import',
'version': '8.0.1.1.0',
'version': '8.0.1.1.1',
'license': 'AGPL-3',
'author': 'Odoo Community Association (OCA), Therp BV',
'website': 'https://github.com/OCA/bank-statement-import',
@ -27,5 +27,5 @@
'depends': [
'account_bank_statement_import',
],
'installable': True
'installable': True,
}

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."""
self.mt940_type = 'General'
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.tag_regex = '^:[0-9]{2}[A-Z]*:' # Start of new tag
self.current_statement = None

2
account_bank_statement_import_mt940_nl_ing/README.rst

@ -7,7 +7,7 @@ Import MT940 IBAN ING Bank Statements
This module allows you to import the MT940 IBAN files from the Dutch ING bank
in Odoo as bank statements.
The specifications are published at:
https://www.ing.nl/media/ING_ming_mt940s_24_juli_tcm162-46356.pdf
https://www.ing.nl/media/ING_ming_mt940s_24_juli_tcm162-46356.pdf
and were last updated august 2014.
Known issues / Roadmap

1
account_bank_statement_import_mt940_nl_ing/__init__.py

@ -1 +1,2 @@
# -*- coding: utf-8 -*-
from . import account_bank_statement_import

4
account_bank_statement_import_mt940_nl_ing/__openerp__.py

@ -19,7 +19,7 @@
##############################################################################
{
'name': 'MT940 IBAN ING Format Bank Statements Import',
'version': '8.0.0.3.0',
'version': '8.0.0.4.0',
'license': 'AGPL-3',
'author': 'Odoo Community Association (OCA), Therp BV',
'website': 'https://github.com/OCA/bank-statement-import',
@ -30,5 +30,5 @@
'demo': [
'demo/demo_data.xml',
],
'installable': True
'installable': True,
}

4
account_bank_statement_import_mt940_nl_ing/tests/__init__.py

@ -1,4 +1,4 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
"""Test import of bank statement for MT940 ING."""
##############################################################################
#
@ -6,8 +6,6 @@
#
# All other contributions are (C) by their respective contributors
#
# All Rights Reserved
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the

2
account_bank_statement_import_mt940_nl_rabo/__init__.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Copyright (C) 2014-2015 Therp BV (<http://therp.nl>).
# Copyright (C) 2014-2015 Therp BV <http://therp.nl>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as

3
account_bank_statement_import_mt940_nl_rabo/__openerp__.py

@ -19,7 +19,8 @@
##############################################################################
{
'name': 'MT940 import for dutch Rabobank',
'version': '8.0.1.1.0',
'version': '8.0.1.1.1',
'license': 'AGPL-3',
'author': 'Odoo Community Association (OCA), Therp BV',
'website': 'https://github.com/OCA/bank-statement-import',
'category': 'Banking addons',

5
account_bank_statement_import_ofx/__openerp__.py

@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-
# -*- coding: utf-8 -*-
{
'name': 'Import OFX Bank Statement',
'category': 'Banking addons',
'version': '8.0.1.0.0',
'version': '8.0.1.0.1',
'license': 'AGPL-3',
'author': 'OpenERP SA,'
'Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/bank-statement-import',

8
account_bank_statement_import_ofx/account_bank_statement_import_ofx.py

@ -5,7 +5,7 @@ import StringIO
from openerp import api, models
from openerp.tools.translate import _
from openerp.exceptions import Warning
from openerp.exceptions import Warning as UserError
_logger = logging.getLogger(__name__)
@ -64,8 +64,10 @@ class AccountBankStatementImport(models.TransientModel):
total_amt += float(transaction.amount)
transactions.append(vals_line)
except Exception, e:
raise Warning(_("The following problem occurred during import. "
"The file might not be valid.\n\n %s" % e.message))
raise UserError(_(
"The following problem occurred during import. "
"The file might not be valid.\n\n %s" % e.message
))
vals_bank_statement = {
'name': ofx.account.routing_number,

4
account_bank_statement_import_qif/__openerp__.py

@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
{
'name': 'Import QIF Bank Statement',
'category': 'Banking addons',
'version': '8.0.1.0.0',
'version': '8.0.1.0.1',
'license': 'AGPL-3',
'author': 'OpenERP SA,'
'Odoo Community Association (OCA)',
'website': 'https://github.com/OCA/bank-statement-import',

10
account_bank_statement_import_qif/account_bank_statement_import_qif.py

@ -5,7 +5,7 @@ import StringIO
from openerp.tools.translate import _
from openerp import api, models
from openerp.exceptions import Warning
from openerp.exceptions import Warning as UserError
class AccountBankStatementImport(models.TransientModel):
@ -36,7 +36,7 @@ class AccountBankStatementImport(models.TransientModel):
header = data_list[0].strip()
header = header.split(":")[1]
except:
raise Warning(_('Could not decipher the QIF file.'))
raise UserError(_('Could not decipher the QIF file.'))
transactions = []
vals_line = {}
total = 0
@ -80,8 +80,10 @@ class AccountBankStatementImport(models.TransientModel):
else:
pass
else:
raise Warning(_('This file is either not a bank statement or is '
'not correctly formed.'))
raise UserError(_(
"This file is either not a bank statement or is "
"not correctly formed."
))
vals_bank_statement.update({
'balance_end_real': total,

36
account_bank_statement_import_save_file/__openerp__.py

@ -1,8 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# OpenERP, Open Source Management Solution
# This module copyright (C) 2015 Therp BV <http://therp.nl>.
# Copyright (C) 2015 Therp BV <http://therp.nl>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -19,27 +18,20 @@
#
##############################################################################
{
"name": "Save imported bank statements",
"version": "8.0.1.0.0",
"author": "Therp BV",
"license": "AGPL-3",
"category": "Accounting & Finance",
"summary": "Keep imported bank statements as raw data",
"depends": [
'name': 'Save imported bank statements',
'version': '8.0.1.0.1',
'author': 'Odoo Community Association (OCA), Therp BV',
'license': 'AGPL-3',
'category': 'Banking addons',
'summary': 'Keep imported bank statements as raw data',
'depends': [
'account_bank_statement_import',
],
"data": [
"views/account_bank_statement.xml",
'data': [
'views/account_bank_statement.xml',
],
"qweb": [
],
"test": [
],
"post_init_hook": '_post_init_hook',
"auto_install": False,
"installable": True,
"application": False,
"external_dependencies": {
'python': [],
},
'post_init_hook': '_post_init_hook',
'auto_install': False,
'installable': True,
'application': False,
}

31
base_bank_account_number_unique/README.rst

@ -1,20 +1,35 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:alt: License: AGPL-3
Unique bank account numbers
===========================
It can be desirable to be able to rely on a bank account number identifying exactly one partner. This module allows you to enforce this, so that an account number is unique in the system.
It can be desirable to be able to rely on a bank account number identifying
exactly one partner. This module allows you to enforce this, so that an
account number is unique in the system.
Installation
============
During installation, the module checks if your bank account numbers are unique already. If this is not the case, you won't be able to install the module until duplicates are fixed.
The error message only shows the first few duplicates, in order to find all of them, use the following statement::
with res_partner_bank_sanitized as (select id, acc_number, regexp_replace(acc_number, '\W+', '', 'g') acc_number_sanitized from res_partner_bank),
res_partner_bank_sanitized_grouped as (select array_agg(id) ids, acc_number_sanitized, count(*) amount from res_partner_bank_sanitized group by acc_number_sanitized)
select * from res_partner_bank_sanitized_grouped where amount > 1;
During installation, the module checks if your bank account numbers are
unique already. If this is not the case, you won't be able to install the
module until duplicates are fixed.
The error message only shows the first few duplicates, in order to find all
of them, use the following statement::
with res_partner_bank_sanitized as (
select
id, acc_number,
regexp_replace(acc_number, '\W+', '', 'g') acc_number_sanitized
from res_partner_bank
),
res_partner_bank_sanitized_grouped as (
select
array_agg(id) ids, acc_number_sanitized, count(*) amount
from res_partner_bank_sanitized group by acc_number_sanitized
)
select * from res_partner_bank_sanitized_grouped where amount > 1;
Bug Tracker
===========

22
base_bank_account_number_unique/__openerp__.py

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# This module copyright (C) 2015 Therp BV <http://therp.nl>.
# Copyright (C) 2015 Therp BV <http://therp.nl>.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
@ -18,16 +18,16 @@
#
##############################################################################
{
"name": "Unique bank account numbers",
"version": "8.0.1.0.0",
"author": "Therp BV,Odoo Community Association (OCA)",
"license": "AGPL-3",
"category": "Accounting & Finance",
"summary": "Enforce uniqueness on bank accounts",
"depends": [
'name': 'Unique bank account numbers',
'version': '8.0.1.0.1',
'author': 'Therp BV, Odoo Community Association (OCA)',
'license': 'AGPL-3',
'category': 'Banking addons',
'summary': 'Enforce uniqueness on bank accounts',
'depends': [
'account_bank_statement_import',
],
"post_init_hook": "post_init_hook",
"auto_install": False,
"installable": True,
'post_init_hook': 'post_init_hook',
'auto_install': False,
'installable': True,
}

7
base_bank_account_number_unique/hooks.py

@ -17,11 +17,12 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
##############################################################################
from openerp import _, SUPERUSER_ID, exceptions
from openerp import _, SUPERUSER_ID
from openerp.exceptions import Warning as UserError
def post_init_hook(cr, pool):
'''check if your constraint was actually inserted, raise otherwise'''
"""check if your constraint was actually inserted, raise otherwise"""
if not pool['ir.model.constraint'].search(cr, SUPERUSER_ID, [
('name', '=', 'res_partner_bank_unique_number'),
('model.model', '=', 'res.partner.bank'),
@ -51,4 +52,4 @@ def post_init_hook(cr, pool):
max_account_numbers, '\n'.join(duplicates),
max_account_numbers,
)
raise exceptions.Warning(message)
raise UserError(message)

4
base_bank_account_number_unique/tests/test_base_bank_account_number_unique.py

@ -18,7 +18,7 @@
#
##############################################################################
from openerp.tests.common import TransactionCase
from openerp import exceptions
from openerp.exceptions import Warning as UserError
from ..hooks import post_init_hook
@ -38,5 +38,5 @@ class TestBaseBankAccountNumberUnique(TransactionCase):
'acc_number': 'BE 1234 567 890',
'state': 'bank',
})
with self.assertRaises(exceptions.Warning):
with self.assertRaises(UserError):
post_init_hook(self.cr, self.registry)
Loading…
Cancel
Save