1
# -*- encoding: utf-8 -*-
2
##############################################################################
4
# Copyright (C) 2009 EduSense BV (<http://www.edusense.nl>).
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# GNU General Public License for more details.
17
# You should have received a copy of the GNU General Public License
18
# along with this program. If not, see <http://www.gnu.org/licenses/>.
20
##############################################################################
22
from tools.translate import _
27
'get_or_create_partner',
28
'get_company_bank_account',
29
'create_bank_account',
35
Ease working with dicts. Allow dict.key alongside dict['key']
37
def __setattr__(self, item, value):
38
self.__setitem__(item, value)
40
def __getattr__(self, item):
41
return self.__getitem__(item)
43
def show(self, indent=0, align=False, ralign=False):
45
PrettyPrint method. Aligns keys right (ralign) or left (align).
49
for key in self.iterkeys():
50
width = max(width, len(key))
54
fmt = '%*.*s%%%s%d.%ds: %%s' % (
55
indent, indent, '', alignment, width, width
58
fmt = '%*.*s%%s: %%s' % (indent, indent, '')
59
for item in self.iteritems():
63
from account_banking import sepa
64
from account_banking.parsers.convert import *
66
def get_period(pool, cursor, uid, date, company, log):
68
Get a suitable period for the given date range and the given company.
70
fiscalyear_obj = pool.get('account.fiscalyear')
71
period_obj = pool.get('account.period')
73
date = date2str(datetime.datetime.today())
75
search_date = date2str(date)
76
fiscalyear_ids = fiscalyear_obj.search(cursor, uid, [
77
('date_start','<=', search_date), ('date_stop','>=', search_date),
78
('state','=','draft'), ('company_id','=',company.id)
80
if not fiscalyear_ids:
81
fiscalyear_ids = fiscalyear_obj.search(cursor, uid, [
82
('date_start','<=',search_date), ('date_stop','>=',search_date),
83
('state','=','draft'), ('company_id','=',None)
85
if not fiscalyear_ids:
87
_('No suitable fiscal year found for company %(company_name)s')
88
% dict(company_name=company.name)
91
elif len(fiscalyear_ids) > 1:
93
_('Multiple overlapping fiscal years found for date %(date)s')
98
fiscalyear_id = fiscalyear_ids[0]
99
period_ids = period_obj.search(cursor, uid, [
100
('date_start','<=',search_date), ('date_stop','>=',search_date),
101
('fiscalyear_id','=',fiscalyear_id), ('state','=','draft')
104
log.append(_('No suitable period found for date %(date)s')
108
if len(period_ids) != 1:
109
log.append(_('Multiple overlapping periods for date %(date)s')
115
def get_bank_account(pool, cursor, uid, account_number, log, fail=False):
117
Get the bank account with account number account_number
119
# No need to search for nothing
120
if not account_number:
123
partner_bank_obj = pool.get('res.partner.bank')
124
bank_account_ids = partner_bank_obj.search(cursor, uid, [
125
('acc_number', '=', account_number)
127
if not bank_account_ids:
128
bank_account_ids = partner_bank_obj.search(cursor, uid, [
129
('iban', '=', account_number)
131
if not bank_account_ids:
134
_('Bank account %(account_no)s was not found in the database')
135
% dict(account_no=account_number)
138
elif len(bank_account_ids) != 1:
140
_('More than one bank account was found with the same number %(account_no)s')
141
% dict(account_no=account_number)
144
return partner_bank_obj.browse(cursor, uid, bank_account_ids)[0]
146
def get_or_create_partner(pool, cursor, uid, name, log):
148
Get or create the partner belonging to the account holders name <name>
150
partner_obj = pool.get('res.partner')
151
partner_ids = partner_obj.search(cursor, uid, [('name', 'ilike', name)])
153
partner_id = partner_obj.create(cursor, uid, dict(
154
name=name, active=True, comment='Generated by Import Bank Statements File',
156
elif len(partner_ids) > 1:
158
_('More then one possible match found for partner with name %(name)s')
163
partner_id = partner_ids[0]
164
return partner_obj.browse(cursor, uid, partner_id)[0]
166
def get_company_bank_account(pool, cursor, uid, account_number,
169
Get the matching bank account for this company.
172
bank_account = get_bank_account(pool, cursor, uid, account_number, log,
176
if bank_account.partner_id.id != company.partner_id.id:
178
_('Account %(account_no)s is not owned by %(partner)s')
179
% dict(account_no = account_number,
180
partner = company.partner_id.name,
183
results.account = bank_account
184
bank_settings_obj = pool.get('account.banking.account.settings')
185
bank_settings_ids = bank_settings_obj.search(cursor, uid, [
186
('partner_bank_id', '=', bank_account.id)
188
if bank_settings_ids:
189
settings = bank_settings_obj.browse(cursor, uid, bank_settings_ids)[0]
190
results.journal_id = settings.journal_id
191
results.default_debit_account_id = settings.default_debit_account_id
192
results.default_credit_account_id = settings.default_credit_account_id
195
def get_iban_bic_NL(bank_acc):
197
Consult the Dutch online banking database to check both the account number
198
and the bank to which it belongs. Will not work offline, is limited to
199
banks operating in the Netherlands and will only convert Dutch local
202
import urllib, urllib2
203
from BeautifulSoup import BeautifulSoup
205
IBANlink = 'http://www.ibannl.org/iban_check.php'
206
data = urllib.urlencode(dict(number=bank_acc, method='POST'))
207
request = urllib2.Request(IBANlink, data)
208
response = urllib2.urlopen(request)
209
soup = BeautifulSoup(response)
211
for _pass, td in enumerate(soup.findAll('td')):
213
result[attr] = td.find('font').contents[0]
215
attr = td.find('strong').contents[0][:4].strip().lower()
217
result.account = bank_acc
218
result.country_id = result.bic[4:6]
219
# Nationalized bank code
220
result.code = result.bic[:6]
221
# All Dutch banks use generic channels
226
online_account_info = {
227
# TODO: Add more online data banks
228
'NL': get_iban_bic_NL,
231
def create_bank_account(pool, cursor, uid, partner_id,
232
account_number, holder_name, log
235
Create a matching bank account with this holder for this partner.
238
partner_id = partner_id,
239
owner_name = holder_name,
241
# Are we dealing with IBAN?
242
iban = sepa.IBAN(account_number)
244
values.state = 'iban'
245
values.acc_number = iban.BBAN
246
bankcode = iban.bankcode + iban.countrycode
248
# No, try to convert to IBAN
249
country = pool.get('res.partner').browse(
250
cursor, uid, partner_id).country_id
251
values.state = 'bank'
252
values.acc_number = account_number
253
if country.code in sepa.IBAN.countries \
254
and country.code in online_account_info \
256
account_info = online_account_info[country.code](values.acc_number)
257
if account_info and iban in account_info:
258
values.iban = iban = account_info.iban
259
values.state = 'iban'
260
bankcode = account_info.code
261
bic = account_info.bic
268
bank_obj = pool.get('res.bank')
269
bank_ids = bank_obj.search(cursor, uid, [
270
('code', 'ilike', bankcode)
272
if not bank_ids and bic:
273
bank_ids = bank_obj.search(cursor, uid, [
274
('bic', 'ilike', bic)
277
# Check BIC on existing banks
278
values.bank_id = bank_ids[0]
279
bank = bank_obj.browse(cursor, uid, values.bank_id)
281
bank_obj.write(cursor, uid, values.bank_id, dict(bic=bic))
284
values.bank_id = bank_obj.create(cursor, uid, dict(
285
code = account_info.code,
286
bic = account_info.bic,
287
name = account_info.bank,
288
country_id = country.id,
291
# Create bank account and return
292
return pool.get('res.partner.bank').create(cursor, uid, values)
294
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: