mirror of
https://github.com/OCA/bank-payment.git
synced 2025-02-02 10:37:31 +02:00
Splitting off the online account number (i.e. IBAN) lookup functionality into a separate module
This commit is contained in:
@@ -31,5 +31,7 @@ import account_banking
|
||||
import parsers
|
||||
import wizard
|
||||
import res_partner
|
||||
import res_bank
|
||||
import res_partner_bank
|
||||
|
||||
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
|
||||
|
||||
@@ -26,14 +26,13 @@
|
||||
|
||||
{
|
||||
'name': 'Account Banking',
|
||||
'version': '0.1.136',
|
||||
'version': '0.2',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Banking addons community',
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account_voucher',
|
||||
'account_iban_preserve_domestic',
|
||||
],
|
||||
'data': [
|
||||
'security/ir.model.access.csv',
|
||||
@@ -47,14 +46,9 @@
|
||||
'js': [
|
||||
'static/src/js/account_banking.js',
|
||||
],
|
||||
'external_dependencies': {
|
||||
'python' : ['BeautifulSoup'],
|
||||
},
|
||||
'description': '''
|
||||
Module to do banking.
|
||||
|
||||
Note: This module is depending on BeautifulSoup.
|
||||
|
||||
This modules tries to combine all current banking import and export
|
||||
schemes. Rationale for this is that it is quite common to have foreign
|
||||
bank account numbers next to national bank account numbers. The current
|
||||
|
||||
@@ -65,14 +65,8 @@ Modifications are extensive:
|
||||
from openerp.osv import orm, fields
|
||||
from openerp.osv.osv import except_osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp import netsvc, SUPERUSER_ID
|
||||
from openerp import netsvc
|
||||
from openerp.addons.decimal_precision import decimal_precision as dp
|
||||
from openerp.addons.account_banking import sepa
|
||||
from openerp.addons.account_banking.wizard.banktools import get_or_create_bank
|
||||
|
||||
def warning(title, message):
|
||||
'''Convenience routine'''
|
||||
return {'warning': {'title': title, 'message': message}}
|
||||
|
||||
|
||||
class account_banking_account_settings(orm.Model):
|
||||
@@ -559,408 +553,6 @@ class account_bank_statement_line(orm.Model):
|
||||
'currency': _get_currency,
|
||||
}
|
||||
|
||||
account_bank_statement_line()
|
||||
|
||||
|
||||
class res_partner_bank(orm.Model):
|
||||
'''
|
||||
This is a hack to circumvent the very limited but widely used base_iban
|
||||
dependency. The usage of __mro__ requires inside information of
|
||||
inheritence. This code is tested and works - it bypasses base_iban
|
||||
altogether. Be sure to use 'super' for inherited classes from here though.
|
||||
|
||||
Extended functionality:
|
||||
1. BBAN and IBAN are considered equal
|
||||
2. Online databases are checked when available
|
||||
3. Banks are created on the fly when using IBAN
|
||||
4. Storage is uppercase, not lowercase
|
||||
5. Presentation is formal IBAN
|
||||
6. BBAN's are generated from IBAN when possible
|
||||
7. In the absence of online databanks, BBAN's are checked on format
|
||||
using IBAN specs.
|
||||
'''
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
'''
|
||||
Locate founder (first non inherited class) in inheritance tree.
|
||||
Defaults to super()
|
||||
Algorithm should prevent moving unknown classes between
|
||||
base.res_partner_bank and this module's res_partner_bank.
|
||||
'''
|
||||
self._founder = super(res_partner_bank, self)
|
||||
self._founder.__init__(*args, **kwargs)
|
||||
mro = self.__class__.__mro__
|
||||
for i in range(len(mro)):
|
||||
if mro[i].__module__.startswith('openerp.addons.base.'):
|
||||
self._founder = mro[i]
|
||||
break
|
||||
|
||||
def init(self, cr):
|
||||
'''
|
||||
Update existing iban accounts to comply to new regime
|
||||
'''
|
||||
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
bank_ids = partner_bank_obj.search(
|
||||
cr, SUPERUSER_ID, [('state', '=', 'iban')], limit=0)
|
||||
for bank in partner_bank_obj.read(cr, SUPERUSER_ID, bank_ids):
|
||||
write_vals = {}
|
||||
if bank['state'] == 'iban':
|
||||
iban_acc = sepa.IBAN(bank['acc_number'])
|
||||
if iban_acc.valid:
|
||||
write_vals['acc_number_domestic'] = iban_acc.localized_BBAN
|
||||
write_vals['acc_number'] = str(iban_acc)
|
||||
elif bank['acc_number'] != bank['acc_number'].upper():
|
||||
write_vals['acc_number'] = bank['acc_number'].upper()
|
||||
if write_vals:
|
||||
partner_bank_obj.write(
|
||||
cr, SUPERUSER_ID, bank['id'], write_vals)
|
||||
|
||||
@staticmethod
|
||||
def _correct_IBAN(acc_number):
|
||||
'''
|
||||
Routine to correct IBAN values and deduce localized values when valid.
|
||||
Note: No check on validity IBAN/Country
|
||||
'''
|
||||
iban = sepa.IBAN(acc_number)
|
||||
return (str(iban), iban.localized_BBAN)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
'''
|
||||
Create dual function IBAN account for SEPA countries
|
||||
'''
|
||||
if vals.get('state') == 'iban':
|
||||
iban = (vals.get('acc_number')
|
||||
or vals.get('acc_number_domestic', False))
|
||||
vals['acc_number'], vals['acc_number_domestic'] = (
|
||||
self._correct_IBAN(iban))
|
||||
return self._founder.create(self, cr, uid, vals, context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
'''
|
||||
Create dual function IBAN account for SEPA countries
|
||||
|
||||
Update the domestic account number when the IBAN is
|
||||
written, or clear the domestic number on regular account numbers.
|
||||
'''
|
||||
if ids and isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
for account in self.read(
|
||||
cr, uid, ids, ['state', 'acc_number']):
|
||||
if 'state' in vals or 'acc_number' in vals:
|
||||
account.update(vals)
|
||||
if account['state'] == 'iban':
|
||||
vals['acc_number'], vals['acc_number_domestic'] = (
|
||||
self._correct_IBAN(account['acc_number']))
|
||||
else:
|
||||
vals['acc_number_domestic'] = False
|
||||
self._founder.write(self, cr, uid, account['id'], vals, context)
|
||||
return True
|
||||
|
||||
def search(self, cr, uid, args, *rest, **kwargs):
|
||||
'''
|
||||
Overwrite search, as both acc_number and iban now can be filled, so
|
||||
the original base_iban 'search and search again fuzzy' tactic now can
|
||||
result in doubled findings. Also there is now enough info to search
|
||||
for local accounts when a valid IBAN was supplied.
|
||||
|
||||
Chosen strategy: create complex filter to find all results in just
|
||||
one search
|
||||
'''
|
||||
|
||||
def is_term(arg):
|
||||
'''Flag an arg as term or otherwise'''
|
||||
return isinstance(arg, (list, tuple)) and len(arg) == 3
|
||||
|
||||
def extended_filter_term(term):
|
||||
'''
|
||||
Extend the search criteria in term when appropriate.
|
||||
'''
|
||||
extra_term = None
|
||||
if term[0].lower() == 'acc_number' and term[1] in ('=', '=='):
|
||||
iban = sepa.IBAN(term[2])
|
||||
if iban.valid:
|
||||
bban = iban.localized_BBAN
|
||||
# Prevent empty search filters
|
||||
if bban:
|
||||
extra_term = ('acc_number_domestic', term[1], bban)
|
||||
if extra_term:
|
||||
return ['|', term, extra_term]
|
||||
return [term]
|
||||
|
||||
def extended_search_expression(args):
|
||||
'''
|
||||
Extend the search expression in args when appropriate.
|
||||
The expression itself is in reverse polish notation, so recursion
|
||||
is not needed.
|
||||
'''
|
||||
if not args:
|
||||
return []
|
||||
|
||||
all = []
|
||||
if is_term(args[0]) and len(args) > 1:
|
||||
# Classic filter, implicit '&'
|
||||
all += ['&']
|
||||
|
||||
for arg in args:
|
||||
if is_term(arg):
|
||||
all += extended_filter_term(arg)
|
||||
else:
|
||||
all += arg
|
||||
return all
|
||||
|
||||
# Extend search filter
|
||||
newargs = extended_search_expression(args)
|
||||
|
||||
# Original search
|
||||
results = super(res_partner_bank, self).search(
|
||||
cr, uid, newargs, *rest, **kwargs)
|
||||
return results
|
||||
|
||||
def read(
|
||||
self, cr, uid, ids, fields=None, context=None, load='_classic_read'):
|
||||
'''
|
||||
Convert IBAN electronic format to IBAN display format
|
||||
SR 2012-02-19: do we really need this? Fields are converted upon write already.
|
||||
'''
|
||||
if fields and 'state' not in fields:
|
||||
fields.append('state')
|
||||
records = self._founder.read(self, cr, uid, ids, fields, context, load)
|
||||
is_list = True
|
||||
if not isinstance(records, list):
|
||||
records = [records,]
|
||||
is_list = False
|
||||
for record in records:
|
||||
if 'acc_number' in record and record['state'] == 'iban':
|
||||
record['acc_number'] = unicode(sepa.IBAN(record['acc_number']))
|
||||
if is_list:
|
||||
return records
|
||||
return records[0]
|
||||
|
||||
def check_iban(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
Check IBAN number
|
||||
'''
|
||||
for bank_acc in self.browse(cr, uid, ids, context=context):
|
||||
if bank_acc.state == 'iban' and bank_acc.acc_number:
|
||||
iban = sepa.IBAN(bank_acc.acc_number)
|
||||
if not iban.valid:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_bban_from_iban(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
Return the local bank account number aka BBAN from the IBAN.
|
||||
'''
|
||||
res = {}
|
||||
for record in self.browse(cr, uid, ids, context):
|
||||
if not record.state == 'iban':
|
||||
res[record.id] = False
|
||||
else:
|
||||
iban_acc = sepa.IBAN(record.acc_number)
|
||||
res[record.id] = iban_acc.localized_BBAN
|
||||
return res
|
||||
|
||||
def onchange_acc_number(
|
||||
self, cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None):
|
||||
if state == 'iban':
|
||||
return self.onchange_iban(
|
||||
cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None
|
||||
)
|
||||
else:
|
||||
return self.onchange_domestic(
|
||||
cr, uid, ids, acc_number,
|
||||
partner_id, country_id, context=None
|
||||
)
|
||||
|
||||
def onchange_domestic(
|
||||
self, cr, uid, ids, acc_number,
|
||||
partner_id, country_id, context=None):
|
||||
'''
|
||||
Trigger to find IBAN. When found:
|
||||
1. Reformat BBAN
|
||||
2. Autocomplete bank
|
||||
|
||||
TODO: prevent unnecessary assignment of country_ids and
|
||||
browsing of the country
|
||||
'''
|
||||
if not acc_number:
|
||||
return {}
|
||||
|
||||
values = {}
|
||||
country_obj = self.pool.get('res.country')
|
||||
country_ids = []
|
||||
country = False
|
||||
|
||||
# Pre fill country based on available data. This is just a default
|
||||
# which can be overridden by the user.
|
||||
# 1. Use provided country_id (manually filled)
|
||||
if country_id:
|
||||
country = country_obj.browse(cr, uid, country_id, context=context)
|
||||
country_ids = [country_id]
|
||||
# 2. Use country_id of found bank accounts
|
||||
# This can be usefull when there is no country set in the partners
|
||||
# addresses, but there was a country set in the address for the bank
|
||||
# account itself before this method was triggered.
|
||||
elif ids and len(ids) == 1:
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
partner_bank_id = partner_bank_obj.browse(cr, uid, ids[0], context=context)
|
||||
if partner_bank_id.country_id:
|
||||
country = partner_bank_id.country_id
|
||||
country_ids = [country.id]
|
||||
# 3. Use country_id of default address of partner
|
||||
# The country_id of a bank account is a one time default on creation.
|
||||
# It originates in the same address we are about to check, but
|
||||
# modifications on that address afterwards are not transfered to the
|
||||
# bank account, hence the additional check.
|
||||
elif partner_id:
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
country = partner_obj.browse(cr, uid, partner_id, context=context).country
|
||||
country_ids = country and [country.id] or []
|
||||
# 4. Without any of the above, take the country from the company of
|
||||
# the handling user
|
||||
if not country_ids:
|
||||
user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
|
||||
# Try user companies partner (user no longer has address in 6.1)
|
||||
if (user.company_id and
|
||||
user.company_id.partner_id and
|
||||
user.company_id.partner_id.country
|
||||
):
|
||||
country_ids = [user.company_id.partner_id.country.id]
|
||||
else:
|
||||
if (user.company_id and user.company_id.partner_id and
|
||||
user.company_id.partner_id.country):
|
||||
country_ids = [user.company_id.partner_id.country.id]
|
||||
else:
|
||||
# Ok, tried everything, give up and leave it to the user
|
||||
return warning(_('Insufficient data'),
|
||||
_('Insufficient data to select online '
|
||||
'conversion database')
|
||||
)
|
||||
result = {'value': values}
|
||||
# Complete data with online database when available
|
||||
if country_ids:
|
||||
country = country_obj.browse(
|
||||
cr, uid, country_ids[0], context=context)
|
||||
values['country_id'] = country_ids[0]
|
||||
if country and country.code in sepa.IBAN.countries:
|
||||
info = sepa.online.account_info(country.code, acc_number)
|
||||
if info:
|
||||
iban_acc = sepa.IBAN(info.iban)
|
||||
if iban_acc.valid:
|
||||
values['acc_number_domestic'] = iban_acc.localized_BBAN
|
||||
values['acc_number'] = unicode(iban_acc)
|
||||
values['state'] = 'iban'
|
||||
bank_id, country_id = get_or_create_bank(
|
||||
self.pool, cr, uid,
|
||||
info.bic or iban_acc.BIC_searchkey,
|
||||
name = info.bank
|
||||
)
|
||||
if country_id:
|
||||
values['country_id'] = country_id
|
||||
values['bank'] = bank_id or False
|
||||
if info.bic:
|
||||
values['bank_bic'] = info.bic
|
||||
else:
|
||||
info = None
|
||||
if info is None:
|
||||
result.update(warning(
|
||||
_('Invalid data'),
|
||||
_('The account number appears to be invalid for %s')
|
||||
% country.name
|
||||
))
|
||||
if info is False:
|
||||
if country.code in sepa.IBAN.countries:
|
||||
acc_number_fmt = sepa.BBAN(acc_number, country.code)
|
||||
if acc_number_fmt.valid:
|
||||
values['acc_number_domestic'] = str(acc_number_fmt)
|
||||
else:
|
||||
result.update(warning(
|
||||
_('Invalid format'),
|
||||
_('The account number has the wrong format '
|
||||
'for %(country)s')
|
||||
% {'country': country.name}
|
||||
))
|
||||
return result
|
||||
|
||||
def onchange_iban(
|
||||
self, cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None):
|
||||
'''
|
||||
Trigger to verify IBAN. When valid:
|
||||
1. Extract BBAN as local account
|
||||
2. Auto complete bank
|
||||
'''
|
||||
if not acc_number:
|
||||
return {}
|
||||
|
||||
iban_acc = sepa.IBAN(acc_number)
|
||||
if iban_acc.valid:
|
||||
bank_id, country_id = get_or_create_bank(
|
||||
self.pool, cr, uid, iban_acc.BIC_searchkey,
|
||||
code=iban_acc.BIC_searchkey
|
||||
)
|
||||
return {
|
||||
'value': dict(
|
||||
acc_number_domestic = iban_acc.localized_BBAN,
|
||||
acc_number = unicode(iban_acc),
|
||||
country = country_id or False,
|
||||
bank = bank_id or False,
|
||||
)
|
||||
}
|
||||
return warning(_('Invalid IBAN account number!'),
|
||||
_("The IBAN number doesn't seem to be correct")
|
||||
)
|
||||
|
||||
res_partner_bank()
|
||||
|
||||
|
||||
class res_bank(orm.Model):
|
||||
'''
|
||||
Add a on_change trigger to automagically fill bank details from the
|
||||
online SWIFT database. Allow hand filled names to overrule SWIFT names.
|
||||
'''
|
||||
_inherit = 'res.bank'
|
||||
|
||||
def onchange_bic(self, cr, uid, ids, bic, name, context=None):
|
||||
'''
|
||||
Trigger to auto complete other fields.
|
||||
'''
|
||||
if not bic:
|
||||
return {}
|
||||
|
||||
info, address = sepa.online.bank_info(bic)
|
||||
if not info:
|
||||
return {}
|
||||
|
||||
if address and address.country_id:
|
||||
country_id = self.pool.get('res.country').search(
|
||||
cr, uid, [('code','=',address.country_id)]
|
||||
)
|
||||
country_id = country_id and country_id[0] or False
|
||||
else:
|
||||
country_id = False
|
||||
|
||||
return {
|
||||
'value': dict(
|
||||
# Only the first eight positions of BIC are used for bank
|
||||
# transfers, so ditch the rest.
|
||||
bic = info.bic[:8],
|
||||
street = address.street,
|
||||
street2 =
|
||||
address.has_key('street2') and address.street2 or False,
|
||||
zip = address.zip,
|
||||
city = address.city,
|
||||
country = country_id,
|
||||
name = name and name or info.name,
|
||||
)
|
||||
}
|
||||
|
||||
res_bank()
|
||||
|
||||
|
||||
class invoice(orm.Model):
|
||||
'''
|
||||
|
||||
@@ -289,35 +289,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_partner_bank_account_banking_form_2" model="ir.ui.view">
|
||||
<field name="name">res.partner.bank.form.banking-2</field>
|
||||
<field name="model">res.partner.bank</field>
|
||||
<field name="inherit_id" ref="base.view_partner_bank_form"/>
|
||||
<field name="priority" eval="24"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="acc_number" position="attributes">
|
||||
<attribute name="on_change">onchange_acc_number(acc_number, acc_number_domestic, state, partner_id, country_id)</attribute>
|
||||
</field>
|
||||
<field name="acc_number_domestic" position="attributes">
|
||||
<attribute name="on_change">onchange_domestic(acc_number_domestic, partner_id, country_id)</attribute>
|
||||
</field>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- Set trigger on BIC in res_bank form -->
|
||||
<record id="view_res_bank_account_banking_form_1" model="ir.ui.view">
|
||||
<field name="name">res.bank.form.banking-1</field>
|
||||
<field name="model">res.bank</field>
|
||||
<field name="inherit_id" ref="base.view_res_bank_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bic" position="replace">
|
||||
<field name="bic" on_change="onchange_bic(bic, name)"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_bank_statement_line_tree">
|
||||
<field name="name">Bank statement line tree view</field>
|
||||
<field name="model">account.bank.statement.line</field>
|
||||
|
||||
31
account_banking/res_bank.py
Normal file
31
account_banking/res_bank.py
Normal file
@@ -0,0 +1,31 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright 2011 - 2014 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
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm
|
||||
|
||||
|
||||
class ResBank(orm.Model):
|
||||
_inherit = 'res.bank'
|
||||
|
||||
def online_bank_info(self, cr, uid, bic, context=None):
|
||||
"""
|
||||
API hook for legacy online lookup of BICs,
|
||||
to be removed in OpenERP 8.0.
|
||||
"""
|
||||
return False, False
|
||||
101
account_banking/res_partner_bank.py
Normal file
101
account_banking/res_partner_bank.py
Normal file
@@ -0,0 +1,101 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 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
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm
|
||||
from openerp.addons.account_banking import sepa
|
||||
|
||||
|
||||
class ResPartnerBank(orm.Model):
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
def online_account_info(
|
||||
self, cr, uid, country_code, acc_number, context=None):
|
||||
"""
|
||||
API hook for legacy online lookup of account info,
|
||||
to be removed in OpenERP 8.0.
|
||||
"""
|
||||
return False
|
||||
|
||||
def search(self, cr, uid, args, *rest, **kwargs):
|
||||
"""
|
||||
When a complete IBAN is searched, also search for its BBAN
|
||||
if we have the domestic column. Disregard spaces
|
||||
when comparing IBANs.
|
||||
"""
|
||||
|
||||
def is_term(arg):
|
||||
'''Flag an arg as term or otherwise'''
|
||||
return isinstance(arg, (list, tuple)) and len(arg) == 3
|
||||
|
||||
def extended_filter_term(term):
|
||||
'''
|
||||
Extend the search criteria in term when appropriate.
|
||||
'''
|
||||
result = [term]
|
||||
extra_terms = []
|
||||
if term[0].lower() == 'acc_number' and term[1] in ('=', '=='):
|
||||
iban = sepa.IBAN(term[2])
|
||||
if iban.valid:
|
||||
# Disregard spaces when comparing IBANs
|
||||
cr.execute(
|
||||
"""
|
||||
SELECT id FROM res_partner_bank
|
||||
WHERE replace(acc_number, ' ', '') = %s
|
||||
""", (term[2].replace(' ', ''),))
|
||||
ids = [row[0] for row in cr.fetchall()]
|
||||
result = [('id', 'in', ids)]
|
||||
|
||||
if 'acc_number_domestic' in self._columns:
|
||||
bban = iban.localized_BBAN
|
||||
# Prevent empty search filters
|
||||
if bban:
|
||||
extra_terms.append(
|
||||
('acc_number_domestic', term[1], bban))
|
||||
for extra_term in extra_terms:
|
||||
result = ['|'] + result + [extra_term]
|
||||
return result
|
||||
|
||||
def extended_search_expression(args):
|
||||
'''
|
||||
Extend the search expression in args when appropriate.
|
||||
The expression itself is in reverse polish notation, so recursion
|
||||
is not needed.
|
||||
'''
|
||||
if not args:
|
||||
return []
|
||||
|
||||
result = []
|
||||
if is_term(args[0]) and len(args) > 1:
|
||||
# Classic filter, implicit '&'
|
||||
result += ['&']
|
||||
|
||||
for arg in args:
|
||||
if is_term(arg):
|
||||
result += extended_filter_term(arg)
|
||||
else:
|
||||
result += arg
|
||||
return result
|
||||
|
||||
# Extend search filter
|
||||
newargs = extended_search_expression(args)
|
||||
|
||||
# Original search
|
||||
return super(ResPartnerBank, self).search(
|
||||
cr, uid, newargs, *rest, **kwargs)
|
||||
@@ -19,6 +19,5 @@
|
||||
#
|
||||
##############################################################################
|
||||
import iban
|
||||
import online
|
||||
IBAN = iban.IBAN
|
||||
BBAN = iban.BBAN
|
||||
|
||||
@@ -63,12 +63,6 @@ def get_bank_accounts(pool, cr, uid, account_number, log, fail=False):
|
||||
bank_account_ids = partner_bank_obj.search(cr, uid, [
|
||||
('acc_number', '=', account_number)
|
||||
])
|
||||
if not bank_account_ids:
|
||||
# SR 2012-02-19 does the search() override in res_partner_bank
|
||||
# provides this result on the previous query?
|
||||
bank_account_ids = partner_bank_obj.search(cr, uid, [
|
||||
('acc_number_domestic', '=', account_number)
|
||||
])
|
||||
if not bank_account_ids:
|
||||
if not fail:
|
||||
log.append(
|
||||
@@ -237,7 +231,7 @@ def get_or_create_bank(pool, cr, uid, bic, online=False, code=None,
|
||||
bank_id = False
|
||||
|
||||
if online:
|
||||
info, address = sepa.online.bank_info(bic)
|
||||
info, address = bank_obj.online_bank_info(cr, uid, bic, context=context)
|
||||
if info:
|
||||
bank_id = bank_obj.create(cr, uid, dict(
|
||||
code = info.code,
|
||||
@@ -301,7 +295,6 @@ def create_bank_account(pool, cr, uid, partner_id,
|
||||
owner_name = holder_name,
|
||||
country_id = country_id,
|
||||
)
|
||||
bankcode = None
|
||||
|
||||
# Are we dealing with IBAN?
|
||||
iban = sepa.IBAN(account_number)
|
||||
@@ -309,23 +302,20 @@ def create_bank_account(pool, cr, uid, partner_id,
|
||||
# Take as much info as possible from IBAN
|
||||
values.state = 'iban'
|
||||
values.acc_number = str(iban)
|
||||
values.acc_number_domestic = iban.BBAN
|
||||
bankcode = iban.bankcode + iban.countrycode
|
||||
else:
|
||||
# No, try to convert to IBAN
|
||||
values.state = 'bank'
|
||||
values.acc_number = values.acc_number_domestic = account_number
|
||||
values.acc_number = account_number
|
||||
|
||||
if country_id:
|
||||
country_code = pool.get('res.country').read(
|
||||
cr, uid, country_id, ['code'], context=context)['code']
|
||||
if country_code in sepa.IBAN.countries:
|
||||
account_info = sepa.online.account_info(
|
||||
country_code, values.acc_number)
|
||||
account_info = pool['res.partner.bank'].online_account_info(
|
||||
cr, uid, country_code, values.acc_number, context=context)
|
||||
if account_info:
|
||||
values.acc_number = iban = account_info.iban
|
||||
values.state = 'iban'
|
||||
bankcode = account_info.code
|
||||
bic = account_info.bic
|
||||
|
||||
if bic:
|
||||
|
||||
3
account_banking_iban_lookup/__init__.py
Normal file
3
account_banking_iban_lookup/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
||||
from . import online
|
||||
from . import urlagent
|
||||
from . import model
|
||||
52
account_banking_iban_lookup/__openerp__.py
Normal file
52
account_banking_iban_lookup/__openerp__.py
Normal file
@@ -0,0 +1,52 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 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
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Banking Addons - Iban lookup (legacy)',
|
||||
'version': '0.1',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'Banking addons community',
|
||||
'website': 'https://launchpad.net/banking-addons',
|
||||
'category': 'Banking addons',
|
||||
'depends': [
|
||||
'account_banking',
|
||||
'account_iban_preserve_domestic',
|
||||
],
|
||||
'data': [
|
||||
'view/res_bank.xml',
|
||||
'view/res_partner_bank.xml',
|
||||
],
|
||||
'external_dependencies': {
|
||||
'python': ['BeautifulSoup'],
|
||||
},
|
||||
'description': '''
|
||||
This addons contains the legacy infrastructure for autocompletion of IBANs
|
||||
and BBANs.
|
||||
|
||||
The autocompletion was implemented for Dutch IBANs, but as it turns out
|
||||
the online database that it consults does not get updated. As a result,
|
||||
the autocompletion will come up with outdated IBANs and BICs.
|
||||
|
||||
This module is deprecated and will be dropped in OpenERP 8.0.
|
||||
''',
|
||||
'auto_install': False,
|
||||
'installable': True,
|
||||
}
|
||||
2
account_banking_iban_lookup/model/__init__.py
Normal file
2
account_banking_iban_lookup/model/__init__.py
Normal file
@@ -0,0 +1,2 @@
|
||||
from . import res_bank
|
||||
from . import res_partner_bank
|
||||
63
account_banking_iban_lookup/model/res_bank.py
Normal file
63
account_banking_iban_lookup/model/res_bank.py
Normal file
@@ -0,0 +1,63 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 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
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp.osv import orm
|
||||
from openerp.addons.account_banking_iban_lookup import online
|
||||
|
||||
|
||||
class ResBank(orm.Model):
|
||||
_inherit = 'res.bank'
|
||||
|
||||
def online_bank_info(self, cr, uid, bic, context=None):
|
||||
"""
|
||||
Overwrite existing API hook from account_banking
|
||||
"""
|
||||
return online.bank_info(bic)
|
||||
|
||||
def onchange_bic(
|
||||
self, cr, uid, ids, bic, name, context=None):
|
||||
|
||||
if not bic:
|
||||
return {}
|
||||
|
||||
info, address = online.bank_info(bic)
|
||||
if not info:
|
||||
return {}
|
||||
|
||||
if address and address.country_id:
|
||||
country_ids = self.pool.get('res.country').search(
|
||||
cr, uid, [('code', '=', address.country_id)])
|
||||
country_id = country_ids[0] if country_ids else False
|
||||
else:
|
||||
country_id = False
|
||||
|
||||
return {
|
||||
'value': dict(
|
||||
# Only the first eight positions of BIC are used for bank
|
||||
# transfers, so ditch the rest.
|
||||
bic=info.bic[:8],
|
||||
street=address.street,
|
||||
street2=address.get('street2', False),
|
||||
zip=address.zip,
|
||||
city=address.city,
|
||||
country=country_id,
|
||||
name=name or info.name,
|
||||
)
|
||||
}
|
||||
271
account_banking_iban_lookup/model/res_partner_bank.py
Normal file
271
account_banking_iban_lookup/model/res_partner_bank.py
Normal file
@@ -0,0 +1,271 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
# (C) 2011 - 2014 Therp BV (<http://therp.nl>).
|
||||
#
|
||||
# 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
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
from openerp import SUPERUSER_ID
|
||||
from openerp.osv import orm
|
||||
from openerp.tools.translate import _
|
||||
from openerp.addons.account_banking_iban_lookup import online
|
||||
from openerp.addons.account_banking import sepa
|
||||
from openerp.addons.account_banking.wizard.banktools import get_or_create_bank
|
||||
|
||||
|
||||
def warning(title, message):
|
||||
'''Convenience routine'''
|
||||
return {'warning': {'title': title, 'message': message}}
|
||||
|
||||
|
||||
class res_partner_bank(orm.Model):
|
||||
'''
|
||||
Extended functionality:
|
||||
1. BBAN and IBAN are considered equal
|
||||
2. Online lookup when an API is available (providing NL in this module)
|
||||
3. Banks are created on the fly when using IBAN + online
|
||||
4. IBAN formatting
|
||||
5. BBAN's are generated from IBAN when possible
|
||||
'''
|
||||
_inherit = 'res.partner.bank'
|
||||
|
||||
def init(self, cr):
|
||||
'''
|
||||
Update existing iban accounts to comply to new regime
|
||||
'''
|
||||
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
bank_ids = partner_bank_obj.search(
|
||||
cr, SUPERUSER_ID, [('state', '=', 'iban')], limit=0)
|
||||
for bank in partner_bank_obj.read(cr, SUPERUSER_ID, bank_ids):
|
||||
write_vals = {}
|
||||
if bank['state'] == 'iban':
|
||||
iban_acc = sepa.IBAN(bank['acc_number'])
|
||||
if iban_acc.valid:
|
||||
write_vals['acc_number_domestic'] = iban_acc.localized_BBAN
|
||||
write_vals['acc_number'] = str(iban_acc)
|
||||
elif bank['acc_number'] != bank['acc_number'].upper():
|
||||
write_vals['acc_number'] = bank['acc_number'].upper()
|
||||
if write_vals:
|
||||
partner_bank_obj.write(
|
||||
cr, SUPERUSER_ID, bank['id'], write_vals)
|
||||
|
||||
@staticmethod
|
||||
def _correct_IBAN(acc_number):
|
||||
'''
|
||||
Routine to correct IBAN values and deduce localized values when valid.
|
||||
Note: No check on validity IBAN/Country
|
||||
'''
|
||||
iban = sepa.IBAN(acc_number)
|
||||
return (str(iban), iban.localized_BBAN)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
'''
|
||||
Create dual function IBAN account for SEPA countries
|
||||
'''
|
||||
if vals.get('state') == 'iban':
|
||||
iban = (vals.get('acc_number')
|
||||
or vals.get('acc_number_domestic', False))
|
||||
vals['acc_number'], vals['acc_number_domestic'] = (
|
||||
self._correct_IBAN(iban))
|
||||
return super(res_partner_bank, self).create(
|
||||
cr, uid, vals, context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
'''
|
||||
Create dual function IBAN account for SEPA countries
|
||||
|
||||
Update the domestic account number when the IBAN is
|
||||
written, or clear the domestic number on regular account numbers.
|
||||
'''
|
||||
if ids and isinstance(ids, (int, long)):
|
||||
ids = [ids]
|
||||
for account in self.read(
|
||||
cr, uid, ids, ['state', 'acc_number']):
|
||||
if 'state' in vals or 'acc_number' in vals:
|
||||
account.update(vals)
|
||||
if account['state'] == 'iban':
|
||||
vals['acc_number'], vals['acc_number_domestic'] = (
|
||||
self._correct_IBAN(account['acc_number']))
|
||||
else:
|
||||
vals['acc_number_domestic'] = False
|
||||
super(res_partner_bank, self).write(
|
||||
cr, uid, account['id'], vals, context)
|
||||
return True
|
||||
|
||||
def onchange_acc_number(
|
||||
self, cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None):
|
||||
if state == 'iban':
|
||||
return self.onchange_iban(
|
||||
cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None
|
||||
)
|
||||
else:
|
||||
return self.onchange_domestic(
|
||||
cr, uid, ids, acc_number,
|
||||
partner_id, country_id, context=None
|
||||
)
|
||||
|
||||
def onchange_domestic(
|
||||
self, cr, uid, ids, acc_number,
|
||||
partner_id, country_id, context=None):
|
||||
'''
|
||||
Trigger to find IBAN. When found:
|
||||
1. Reformat BBAN
|
||||
2. Autocomplete bank
|
||||
|
||||
TODO: prevent unnecessary assignment of country_ids and
|
||||
browsing of the country
|
||||
'''
|
||||
if not acc_number:
|
||||
return {}
|
||||
|
||||
values = {}
|
||||
country_obj = self.pool.get('res.country')
|
||||
country_ids = []
|
||||
country = False
|
||||
|
||||
# Pre fill country based on available data. This is just a default
|
||||
# which can be overridden by the user.
|
||||
# 1. Use provided country_id (manually filled)
|
||||
if country_id:
|
||||
country = country_obj.browse(cr, uid, country_id, context=context)
|
||||
country_ids = [country_id]
|
||||
# 2. Use country_id of found bank accounts
|
||||
# This can be usefull when there is no country set in the partners
|
||||
# addresses, but there was a country set in the address for the bank
|
||||
# account itself before this method was triggered.
|
||||
elif ids and len(ids) == 1:
|
||||
partner_bank_obj = self.pool.get('res.partner.bank')
|
||||
partner_bank_id = partner_bank_obj.browse(
|
||||
cr, uid, ids[0], context=context)
|
||||
if partner_bank_id.country_id:
|
||||
country = partner_bank_id.country_id
|
||||
country_ids = [country.id]
|
||||
# 3. Use country_id of default address of partner
|
||||
# The country_id of a bank account is a one time default on creation.
|
||||
# It originates in the same address we are about to check, but
|
||||
# modifications on that address afterwards are not transfered to the
|
||||
# bank account, hence the additional check.
|
||||
elif partner_id:
|
||||
partner_obj = self.pool.get('res.partner')
|
||||
country = partner_obj.browse(
|
||||
cr, uid, partner_id, context=context).country
|
||||
country_ids = country and [country.id] or []
|
||||
# 4. Without any of the above, take the country from the company of
|
||||
# the handling user
|
||||
if not country_ids:
|
||||
user = self.pool.get('res.users').browse(
|
||||
cr, uid, uid, context=context)
|
||||
# Try user companies partner (user no longer has address in 6.1)
|
||||
if (user.company_id and
|
||||
user.company_id.partner_id and
|
||||
user.company_id.partner_id.country):
|
||||
country_ids = [user.company_id.partner_id.country.id]
|
||||
else:
|
||||
if (user.company_id and user.company_id.partner_id and
|
||||
user.company_id.partner_id.country):
|
||||
country_ids = [user.company_id.partner_id.country.id]
|
||||
else:
|
||||
# Ok, tried everything, give up and leave it to the user
|
||||
return warning(_('Insufficient data'),
|
||||
_('Insufficient data to select online '
|
||||
'conversion database')
|
||||
)
|
||||
result = {'value': values}
|
||||
# Complete data with online database when available
|
||||
if country_ids:
|
||||
country = country_obj.browse(
|
||||
cr, uid, country_ids[0], context=context)
|
||||
values['country_id'] = country_ids[0]
|
||||
if country and country.code in sepa.IBAN.countries:
|
||||
info = online.account_info(country.code, acc_number)
|
||||
if info:
|
||||
iban_acc = sepa.IBAN(info.iban)
|
||||
if iban_acc.valid:
|
||||
values['acc_number_domestic'] = iban_acc.localized_BBAN
|
||||
values['acc_number'] = unicode(iban_acc)
|
||||
values['state'] = 'iban'
|
||||
bank_id, country_id = get_or_create_bank(
|
||||
self.pool, cr, uid,
|
||||
info.bic or iban_acc.BIC_searchkey,
|
||||
name=info.bank)
|
||||
if country_id:
|
||||
values['country_id'] = country_id
|
||||
values['bank'] = bank_id or False
|
||||
if info.bic:
|
||||
values['bank_bic'] = info.bic
|
||||
else:
|
||||
info = None
|
||||
if info is None:
|
||||
result.update(warning(
|
||||
_('Invalid data'),
|
||||
_('The account number appears to be invalid for %s')
|
||||
% country.name
|
||||
))
|
||||
if info is False:
|
||||
if country.code in sepa.IBAN.countries:
|
||||
acc_number_fmt = sepa.BBAN(acc_number, country.code)
|
||||
if acc_number_fmt.valid:
|
||||
values['acc_number_domestic'] = str(acc_number_fmt)
|
||||
else:
|
||||
result.update(warning(
|
||||
_('Invalid format'),
|
||||
_('The account number has the wrong format for %s')
|
||||
% country.name
|
||||
))
|
||||
return result
|
||||
|
||||
def onchange_iban(
|
||||
self, cr, uid, ids, acc_number, acc_number_domestic,
|
||||
state, partner_id, country_id, context=None):
|
||||
'''
|
||||
Trigger to verify IBAN. When valid:
|
||||
1. Extract BBAN as local account
|
||||
2. Auto complete bank
|
||||
'''
|
||||
if not acc_number:
|
||||
return {}
|
||||
|
||||
iban_acc = sepa.IBAN(acc_number)
|
||||
if iban_acc.valid:
|
||||
bank_id, country_id = get_or_create_bank(
|
||||
self.pool, cr, uid, iban_acc.BIC_searchkey,
|
||||
code=iban_acc.BIC_searchkey
|
||||
)
|
||||
return {
|
||||
'value': dict(
|
||||
acc_number_domestic=iban_acc.localized_BBAN,
|
||||
acc_number=unicode(iban_acc),
|
||||
country=country_id or False,
|
||||
bank=bank_id or False,
|
||||
)
|
||||
}
|
||||
return warning(
|
||||
_('Invalid IBAN account number!'),
|
||||
_("The IBAN number doesn't seem to be correct"))
|
||||
|
||||
def online_account_info(
|
||||
self, cr, uid, country_code, acc_number, context=None):
|
||||
"""
|
||||
Overwrite API hook from account_banking
|
||||
"""
|
||||
return online.account_info(country_code, acc_number)
|
||||
@@ -1,4 +1,4 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
|
||||
@@ -26,7 +26,7 @@ import re
|
||||
import urllib, urllib2
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
from openerp.addons.account_banking.sepa import postalcode
|
||||
from openerp.addons.account_banking.sepa.urlagent import URLAgent, SoupForm
|
||||
from openerp.addons.account_banking_iban_lookup.urlagent import URLAgent, SoupForm
|
||||
from openerp.addons.account_banking.sepa.iban import IBAN
|
||||
from openerp.addons.account_banking.struct import struct
|
||||
|
||||
@@ -25,7 +25,6 @@ forms and to parse the results back in. It is heavily based on BeautifulSoup.
|
||||
'''
|
||||
|
||||
import urllib
|
||||
from BeautifulSoup import BeautifulSoup
|
||||
|
||||
__all__ = ['urlsplit', 'urljoin', 'pathbase', 'urlbase', 'SoupForm',
|
||||
'URLAgent'
|
||||
15
account_banking_iban_lookup/view/res_bank.xml
Normal file
15
account_banking_iban_lookup/view/res_bank.xml
Normal file
@@ -0,0 +1,15 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_res_bank_account_banking_form_1" model="ir.ui.view">
|
||||
<field name="name">Add BIC lookup to bank form</field>
|
||||
<field name="model">res.bank</field>
|
||||
<field name="inherit_id" ref="base.view_res_bank_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="bic" position="replace">
|
||||
<field name="bic" on_change="onchange_bic(bic, name)"/>
|
||||
</field>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
23
account_banking_iban_lookup/view/res_partner_bank.xml
Normal file
23
account_banking_iban_lookup/view/res_partner_bank.xml
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data>
|
||||
<record id="view_partner_bank_account_banking_form_2" model="ir.ui.view">
|
||||
<field name="name">Add autocompletion methods to partner bank form</field>
|
||||
<field name="model">res.partner.bank</field>
|
||||
<field name="inherit_id" ref="base.view_partner_bank_form"/>
|
||||
<field name="priority" eval="24"/>
|
||||
<field name="arch" type="xml">
|
||||
<data>
|
||||
<field name="acc_number" position="attributes">
|
||||
<attribute name="on_change">onchange_acc_number(acc_number, acc_number_domestic, state, partner_id, country_id)</attribute>
|
||||
</field>
|
||||
<field name="acc_number_domestic" position="attributes">
|
||||
<attribute name="on_change">onchange_domestic(acc_number_domestic, partner_id, country_id)</attribute>
|
||||
</field>
|
||||
</data>
|
||||
</field>
|
||||
</record>
|
||||
</data>
|
||||
</openerp>
|
||||
|
||||
|
||||
@@ -24,7 +24,10 @@
|
||||
'author': 'EduSense BV',
|
||||
'website': 'http://www.edusense.nl',
|
||||
'category': 'Account Banking',
|
||||
'depends': ['account_banking_payment'],
|
||||
'depends': [
|
||||
'account_banking_payment',
|
||||
'account_iban_preserve_domestic',
|
||||
],
|
||||
'data': [
|
||||
'account_banking_nl_clieop.xml',
|
||||
'wizard/export_clieop_view.xml',
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
##############################################################################
|
||||
|
||||
{
|
||||
'name': 'Account Banking',
|
||||
'name': 'Account Banking - NL Multibank import',
|
||||
'version': '0.62',
|
||||
'license': 'AGPL-3',
|
||||
'author': 'EduSense BV',
|
||||
|
||||
@@ -116,14 +116,26 @@ class banking_import_transaction(orm.Model):
|
||||
'''
|
||||
# TODO: Not sure what side effects are created when payments are done
|
||||
# for credited customer invoices, which will be matched later on too.
|
||||
|
||||
def bank_match(account, partner_bank):
|
||||
"""
|
||||
Returns whether a given account number is equivalent to a
|
||||
partner bank in the database. We simply call the search method,
|
||||
which checks IBAN, domestic and disregards from spaces in IBANs.
|
||||
|
||||
:param account: string representation of a bank account number
|
||||
:param partner_bank: browse record of model res.partner.bank
|
||||
"""
|
||||
return partner_bank.id in self.pool['res.partner.bank'].search(
|
||||
cr, uid, [('acc_number', '=', account)])
|
||||
|
||||
digits = dp.get_precision('Account')(cr)[1]
|
||||
candidates = [
|
||||
x for x in payment_lines
|
||||
if x.communication == trans.reference
|
||||
and round(x.amount, digits) == -round(
|
||||
trans.statement_line_id.amount, digits)
|
||||
and trans.remote_account in (x.bank_id.acc_number,
|
||||
x.bank_id.acc_number_domestic)
|
||||
line for line in payment_lines
|
||||
if (line.communication == trans.reference
|
||||
and round(line.amount, digits) == -round(
|
||||
trans.statement_line_id.amount, digits)
|
||||
and bank_match(trans.remote_account, line.bank_id))
|
||||
]
|
||||
if len(candidates) == 1:
|
||||
candidate = candidates[0]
|
||||
|
||||
Reference in New Issue
Block a user