13
13
# This program is distributed in the hope that it will be useful,
14
14
# but WITHOUT ANY WARRANTY; without even the implied warranty of
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
16
# GNU Affero General Public License for more details.
18
18
# You should have received a copy of the GNU Affero General Public License
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
19
# along with this program. If not, see <http://www.gnu.org/licenses/>.
21
21
##############################################################################
23
from openerp.osv import osv, orm, fields
24
from openerp.tools.translate import _
25
from openerp import netsvc
25
from osv import fields,osv
26
from tools.translate import _
29
29
from traceback import format_exception
30
30
from sys import exc_info
32
32
_logger = logging.getLogger(__name__)
34
class account_coda_import(osv.osv_memory):
35
class account_coda_import(orm.TransientModel):
35
36
_name = 'account.coda.import'
36
37
_description = 'Import CODA File'
38
39
'coda_data': fields.binary('CODA File', required=True),
39
40
'coda_fname': fields.char('CODA Filename', size=128, required=True),
41
'period_id': fields.many2one('account.period', 'Force Period',
42
domain=[('state','=','draft'),('special', '=', False)],
43
help="Keep empty to use the period of the bank statement date."),
40
44
'note':fields.text('Log'),
43
47
'coda_fname': lambda *a: '',
50
_skip_undefined = False # Bank Statements which have not been defined in the CODA configuration will be skipped if set to TRUE
46
52
def _check_account_payment(self, cr, uid, context=None):
47
53
res = self.pool.get('ir.module.module').search(cr, uid, [('name', '=', 'account_payment'), ('state','=','installed')])
48
54
return res and True or False
50
def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None):
56
def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None, period_id=None):
51
57
if context is None:
54
61
codafile = str(codafile)
55
62
codafilename = codafilename
57
64
data=self.browse(cr,uid,ids)[0]
59
66
codafile = data.coda_data
60
codafilename = data.coda_fname
67
codafilename = data.coda_fname
68
period_id = data.period_id and data.period_id.id or False
62
raise osv.except_osv(_('Error!'), _('Wizard in incorrect state. Please hit the Cancel button!'))
70
raise orm.except_orm(_('Error!'), _('Wizard in incorrect state. Please hit the Cancel button!'))
65
73
company_obj = self.pool.get('res.company')
194
199
coda_statement['currency_id'] = coda_bank['currency'][0]
195
200
coda_statement['coda_bank_account_id'] = coda_bank['id']
196
201
coda_statement['account_mapping_ids'] = coda_bank['account_mapping_ids']
197
coda_statement['coda_bank_params'] = coda_bank
198
awaiting_acc = coda_bank['awaiting_account'][0]
199
transfer_acc = coda_bank['transfer_account'][0]
200
find_payment = coda_bank['find_payment']
201
find_bbacom = coda_bank['find_bbacom']
202
find_inv_number = coda_bank['find_inv_number']
203
find_partner = coda_bank['find_partner']
204
update_partner = coda_bank['update_partner']
205
coda_statement['balance_start_enforce'] = coda_bank['balance_start_enforce']
206
coda_statement['discard_dup'] = coda_bank['discard_dup']
202
coda_statement['coda_bank_params'] = coda_bank
207
203
coda_statement['company_id'] = coda_bank['company_id'][0]
208
204
context['force_company'] = coda_statement['company_id']
209
company_currency_id = company_obj.read(cr, uid, coda_statement['company_id'], ['currency_id'])['currency_id'][0]
210
205
company_bank_ids = partner_bank_obj.search(cr, uid, [('company_id', '=', coda_statement['company_id'])])
211
206
company_bank_accounts = partner_bank_obj.read(cr, uid, company_bank_ids, ['acc_number'])
212
company_bank_accounts = [x['acc_number'].replace(' ', '') for x in company_bank_accounts]
207
self.company_bank_accounts = [x['acc_number'].replace(' ', '') for x in company_bank_accounts]
208
coda_statement['balance_start_enforce'] = coda_bank['balance_start_enforce']
209
coda_statement['discard_dup'] = coda_bank['discard_dup']
211
if self._skip_undefined:
212
coda_note += _("\n\nNo matching CODA Bank Account Configuration record found !") + \
213
_("\nPlease check if the 'Bank Account Number', 'Currency' and 'Account Description' fields of your configuration record match with '%s', '%s' and '%s' if you need to import statements for this Bank Account Number !") \
214
% (coda_statement['acc_number'], coda_statement['currency'], coda_statement['description'])
214
216
err_string = _("\nNo matching CODA Bank Account Configuration record found !") + \
215
217
_("\nPlease check if the 'Bank Account Number', 'Currency' and 'Account Description' fields of your configuration record match with '%s', '%s' and '%s' !") \
216
218
% (coda_statement['acc_number'], coda_statement['currency'], coda_statement['description'])
217
219
err_code = 'R1004'
219
221
return (err_code, err_string)
220
raise osv.except_osv(_('Data Error!'), err_string)
222
raise orm.except_orm(_('Data Error!'), err_string)
221
223
bal_start = list2float(line[43:58]) # old balance data
224
if coda_bank['state'] == 'skip':
225
coda_note += _("\n\nThe CODA File contains a statement which is not processed since the associated CODA Bank Account Configuration record is defined as type 'Skip' !") + \
226
_("\nPlease adjust the settings for CODA Bank Account '%s' ('Bank Account Number'='%s', 'Currency'='%s' and 'Account Description'='%s') if you need to import statements for this Bank Account !") \
227
% (coda_bank['name'], coda_statement['acc_number'], coda_statement['currency'], coda_statement['description'])
222
229
if line[42] == '1': # 1= Debit
223
230
bal_start = - bal_start
224
231
coda_statement['balance_start'] = bal_start
479
488
err_code = 'R2006'
481
490
return (err_code, err_string)
482
raise osv.except_osv(_('Error!'), err_string)
491
raise orm.except_orm(_('Error!'), err_string)
485
# invoice matching and reconciliation
486
if st_line['type'] == 'general':
488
payment_reference_match = False
490
partner_bank_ids = False
492
# check payment reference in bank statement line against payment order lines
493
payment_reference = st_line['payment_reference']
494
if payment_reference and find_payment and st_line['amount'] < 0:
495
payline_ids = payment_line_obj and payment_line_obj.search(cr, uid, [('name', '=', payment_reference)])
497
if len(payline_ids) == 1:
498
payline = payment_line_obj.browse(cr, uid, payline_ids[0], context=context)
500
payment_reference_match = True
501
st_line['partner_id'] = payline.partner_id.id
502
if payline.move_line_id:
503
st_line['reconcile'] = payline.move_line_id.id
504
st_line['account_id'] = payline.move_line_id.account_id.id
505
if payline._get_ml_inv_ref:
506
inv_type = payline.ml_inv_ref.type
507
st_line['type'] = inv_type == 'in_invoice' and 'supplier' or 'customer'
509
st_line['type'] = 'general'
511
err_string = _('\nThe CODA parsing detected a payment reference ambiguity while processing movement data record 2.3, seq nr %s!' \
512
'\nPlease check your Payment Gateway configuration or contact your OpenERP support channel.') % line[2:10]
515
return (err_code, err_string)
516
raise osv.except_osv(_('Error!'), err_string)
518
# check bba scor in bank statement line against open invoices
519
if st_line['struct_comm_bba'] and find_bbacom:
520
if st_line['amount'] > 0:
521
domain = [('type', 'in', ['out_invoice', 'in_refund'])]
523
domain = [('type', 'in', ['in_invoice', 'out_refund'])]
524
inv_ids = inv_obj.search(cr , uid,
525
domain + [('state', '=', 'open'), ('reference' ,'=', st_line['struct_comm_bba']), ('reference_type' ,'=', 'bba')])
527
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
528
"\n There is no invoice matching the Structured Communication '%s'!") \
529
% (st_line['ref'], st_line['struct_comm_bba'])
530
elif len(inv_ids) == 1:
532
elif len(inv_ids) > 1:
533
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
534
"\n There are multiple invoices matching the Structured Communication '%s'!" \
535
"\n A manual reconciliation is required.") \
536
% (st_line['ref'], st_line['struct_comm_bba'])
538
# use free comm in bank statement line for lookup against open invoices
539
if not match and find_bbacom:
540
# extract possible bba scor from free form communication and try to find matching invoice
541
free_comm_digits = re.sub('\D', '', st_line['communication'] or '')
542
select = "SELECT id FROM (SELECT id, type, state, amount_total, number, reference_type, reference, " \
543
"'%s'::text AS free_comm_digits FROM account_invoice) sq " \
544
"WHERE state = 'open' AND reference_type = 'bba' " \
545
"AND free_comm_digits LIKE '%%'||regexp_replace(reference, '\\\D', '', 'g')||'%%'" \
547
if st_line['amount'] > 0:
548
select2 = " AND type IN ('out_invoice', 'in_refund')"
550
select2 = " AND type IN ('in_invoice', 'out_refund')"
551
cr.execute(select + select2)
554
inv_ids = [x[0] for x in res]
555
if len(inv_ids) == 1:
557
if not match and st_line['communication'] and find_inv_number:
558
# check matching invoice number in free form communication combined with matching amount
559
free_comm = repl_special(st_line['communication'].strip())
560
amount_fmt = '%.' + str(digits) + 'f'
561
if st_line['amount'] > 0:
562
amount_rounded = amount_fmt % round(st_line['amount'], digits)
564
amount_rounded = amount_fmt % round(-st_line['amount'], digits)
565
select = "SELECT id FROM (SELECT id, type, state, amount_total, number, reference_type, reference, " \
566
"'%s'::text AS free_comm FROM account_invoice) sq " \
567
"WHERE state = 'open' AND amount_total = %s" \
568
% (free_comm, amount_rounded)
569
# 'out_invoice', 'in_refund'
570
if st_line['amount'] > 0:
571
select2 = " AND type = 'out_invoice' AND free_comm ilike '%'||number||'%'"
572
cr.execute(select + select2)
575
inv_ids = [x[0] for x in res]
577
select2 = " AND type = 'in_refund' AND free_comm ilike '%'||reference||'%'"
578
cr.execute(select + select2)
581
inv_ids = [x[0] for x in res]
582
# 'in_invoice', 'out_refund'
584
select2 = " AND type = 'in_invoice' AND free_comm ilike '%'||reference||'%'"
585
cr.execute(select + select2)
588
inv_ids = [x[0] for x in res]
590
select2 = " AND type = 'out_refund' AND free_comm ilike '%'||number||'%'"
591
cr.execute(select + select2)
594
inv_ids = [x[0] for x in res]
596
if len(inv_ids) == 1:
598
elif len(inv_ids) > 1:
599
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
600
"\n There are multiple invoices matching the Invoice Amount and Reference." \
601
"\n A manual reconciliation is required.") \
604
if not payment_reference_match and match and inv_ids and len(inv_ids) == 1:
605
invoice = inv_obj.browse(cr, uid, inv_ids[0], context=context)
606
partner = invoice.partner_id
607
st_line['partner_id'] = partner.id
608
if invoice.type in ['in_invoice', 'in_refund']:
609
st_line['account_id'] = partner.property_account_payable.id
610
st_line['type'] = 'supplier'
612
st_line['account_id'] = partner.property_account_receivable.id
613
st_line['type'] = 'customer'
614
iml_ids = move_line_obj.search(cr, uid, [('move_id', '=', invoice.move_id.id), ('reconcile_id', '=', False), ('account_id.reconcile', '=', True)])
616
st_line['reconcile'] = iml_ids[0]
618
err_string = _('\nThe CODA parsing detected a database inconsistency while processing movement data record 2.3, seq nr %s!' \
619
'\nPlease report this issue via your OpenERP support channel.') % line[2:10]
622
return (err_code, err_string)
623
raise osv.except_osv(_('Error!'), err_string)
625
# lookup partner via counterparty_number when invoice lookup failed
626
if not match and counterparty_number:
627
transfer_account = filter(lambda x: counterparty_number in x, company_bank_accounts)
629
st_line['account_id'] = transfer_acc
632
partner_bank_ids = partner_bank_obj.search(cr,uid,[('acc_number','=', counterparty_number)])
633
if not match and find_partner and partner_bank_ids:
634
if len(partner_bank_ids) > 1:
635
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
636
"\n No partner record assigned: There are multiple partners with the same Bank Account Number '%s'!") \
637
% (st_line['ref'], counterparty_number)
639
partner_bank = partner_bank_obj.browse(cr, uid, partner_bank_ids[0], context=context)
640
st_line['partner_id'] = partner_bank.partner_id.id
642
if st_line['amount'] < 0:
643
st_line['account_id'] = partner_bank.partner_id.property_account_payable.id
644
st_line['type'] = 'supplier'
646
st_line['account_id'] = partner_bank.partner_id.property_account_receivable.id
647
st_line['type'] = 'customer'
648
elif not match and find_partner:
649
if counterparty_number:
650
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
651
"\n The bank account '%s' is not defined for the partner '%s'!") \
652
% (st_line['ref'], counterparty_number, counterparty_name)
654
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
655
"\n No matching partner record found!" \
656
"\n Please adjust the corresponding entry manually in the generated Bank Statement.") \
658
st_line['account_id'] = awaiting_acc
660
# add bank account to partner record
661
if match and st_line['account_id'] != transfer_acc and counterparty_number and update_partner:
662
partner_bank_ids = partner_bank_obj.search(cr,uid,[('acc_number','=', counterparty_number), ('partner_id', '=', st_line['partner_id'])], order='id')
663
if len(partner_bank_ids) > 1:
664
# clean up partner bank duplicates, keep most recently created
665
_logger.warn('Duplicate Bank Accounts for partner_id %s have been removed, ids = %s',
666
st_line['partner_id'], partner_bank_ids[:-1])
667
partner_bank_obj.unlink(cr,uid, partner_bank_ids[:-1])
668
if not partner_bank_ids:
669
feedback = update_partner_bank(self, cr, uid, st_line['counterparty_bic'], counterparty_number, st_line['partner_id'], counterparty_name)
671
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':") % st_line['ref'] + feedback
494
if st_line['type'] == 'general':
495
st_line, coda_parsing_note = self._match_and_reconcile(cr, uid, st_line, coda_parsing_note, coda_statement, context=context)
673
497
coda_statement_lines[st_line_seq] = st_line
674
498
coda_statement['coda_statement_lines'] = coda_statement_lines
675
500
# end of processing movement data record 2.3
1377
1210
'type': 'ir.actions.act_window',
1213
def _match_and_reconcile(self, cr, uid, st_line, coda_parsing_note, coda_statement, context=None):
1215
Matching and Reconciliation logic.
1217
Returns: st_line, coda_parsing_note
1220
Don't use 'raise' when the CODA is processed in batch mode (check if self.batch is True)
1223
# match on payment reference
1224
st_line, coda_parsing_note, match = self._match_payment_reference(cr, uid, st_line, coda_parsing_note, coda_statement, context=context)
1226
return st_line, coda_parsing_note
1229
st_line, coda_parsing_note, match = self._match_invoice(cr, uid, st_line, coda_parsing_note, coda_statement, context=context)
1231
return st_line, coda_parsing_note
1233
# match on sale order
1234
st_line, coda_parsing_note, match = self._match_sale_order(cr, uid, st_line, coda_parsing_note, coda_statement, context=context)
1236
return st_line, coda_parsing_note
1238
# check if internal_transfer or partner via counterparty_number when invoice lookup failed
1239
st_line, coda_parsing_note, match = self._match_counterparty(cr, uid, st_line, coda_parsing_note, coda_statement, context=context)
1241
return st_line, coda_parsing_note
1243
return st_line, coda_parsing_note
1245
def _match_payment_reference(self, cr, uid, st_line, coda_parsing_note, coda_statement, context=None):
1246
""" placeholder for ISO 20022 Payment Order matching, cf. module account_coda_pain """
1247
return st_line, coda_parsing_note, {}
1249
def _match_sale_order(self, cr, uid, st_line, coda_parsing_note, coda_statement, context=None):
1250
""" placeholder for sale order matching, cf. module account_coda_sale """
1251
return st_line, coda_parsing_note, {}
1253
def _match_invoice(self, cr, uid, st_line, coda_parsing_note, coda_statement, context=None):
1255
coda_bank_params = coda_statement['coda_bank_params']
1256
find_bbacom = coda_bank_params['find_bbacom']
1257
find_inv_number = coda_bank_params['find_inv_number']
1259
inv_obj = self.pool.get('account.invoice')
1260
move_line_obj = self.pool.get('account.move.line')
1264
# check bba scor in bank statement line against open invoices
1265
if st_line['struct_comm_bba'] and find_bbacom:
1266
if st_line['amount'] > 0:
1267
domain = [('type', 'in', ['out_invoice', 'in_refund'])]
1269
domain = [('type', 'in', ['in_invoice', 'out_refund'])]
1270
inv_ids = inv_obj.search(cr , uid,
1271
domain + [('state', '=', 'open'), ('reference' ,'=', st_line['struct_comm_bba']), ('reference_type' ,'=', 'bba')])
1273
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
1274
"\n There is no invoice matching the Structured Communication '%s'!") \
1275
% (st_line['ref'], st_line['struct_comm_bba'])
1276
elif len(inv_ids) == 1:
1277
match['invoice_id'] = inv_ids[0]
1278
elif len(inv_ids) > 1:
1279
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
1280
"\n There are multiple invoices matching the Structured Communication '%s'!" \
1281
"\n A manual reconciliation is required.") \
1282
% (st_line['ref'], st_line['struct_comm_bba'])
1284
# use free comm in bank statement line for lookup against open invoices
1285
if not match and find_bbacom:
1286
# extract possible bba scor from free form communication and try to find matching invoice
1287
free_comm_digits = re.sub('\D', '', st_line['communication'] or '')
1288
select = "SELECT id FROM (SELECT id, type, state, amount_total, number, reference_type, reference, " \
1289
"'%s'::text AS free_comm_digits FROM account_invoice) sq " \
1290
"WHERE state = 'open' AND reference_type = 'bba' " \
1291
"AND free_comm_digits LIKE '%%'||regexp_replace(reference, '\\\D', '', 'g')||'%%'" \
1292
% (free_comm_digits)
1293
if st_line['amount'] > 0:
1294
select2 = " AND type IN ('out_invoice', 'in_refund')"
1296
select2 = " AND type IN ('in_invoice', 'out_refund')"
1297
cr.execute(select + select2)
1300
inv_ids = [x[0] for x in res]
1301
if len(inv_ids) == 1:
1302
match['invoice_id'] = inv_ids[0]
1303
if not match and st_line['communication'] and find_inv_number:
1304
# check matching invoice number in free form communication combined with matching amount
1305
free_comm = repl_special(st_line['communication'].strip())
1306
amount_fmt = '%.' + str(self.digits) + 'f'
1307
if st_line['amount'] > 0:
1308
amount_rounded = amount_fmt % round(st_line['amount'], self.digits)
1310
amount_rounded = amount_fmt % round(-st_line['amount'], self.digits)
1311
select = "SELECT id FROM (SELECT id, type, state, amount_total, number, reference_type, reference, " \
1312
"'%s'::text AS free_comm FROM account_invoice WHERE state = 'open' AND company_id = %s) sq " \
1313
"WHERE amount_total = %s" \
1314
% (free_comm, coda_statement['company_id'], amount_rounded)
1316
# 'out_invoice', 'in_refund'
1317
if st_line['amount'] > 0:
1318
select2 = " AND type = 'out_invoice' AND free_comm ilike '%'||number||'%'"
1319
cr.execute(select + select2)
1322
inv_ids = [x[0] for x in res]
1324
select2 = " AND type = 'in_refund' AND free_comm ilike '%'||reference||'%'"
1325
cr.execute(select + select2)
1328
inv_ids = [x[0] for x in res]
1330
# 'in_invoice', 'out_refund'
1332
select2 = " AND type = 'in_invoice' AND free_comm ilike '%'||reference||'%'"
1333
cr.execute(select + select2)
1336
inv_ids = [x[0] for x in res]
1338
select2 = " AND type = 'out_refund' AND free_comm ilike '%'||number||'%'"
1339
cr.execute(select + select2)
1342
inv_ids = [x[0] for x in res]
1344
if len(inv_ids) == 1:
1345
match['invoice_id'] = inv_ids[0]
1346
elif len(inv_ids) > 1:
1347
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
1348
"\n There are multiple invoices matching the Invoice Amount and Reference." \
1349
"\n A manual reconciliation is required.") \
1353
invoice = inv_obj.browse(cr, uid, inv_ids[0], context=context)
1354
partner = invoice.partner_id
1355
st_line['partner_id'] = partner.id
1356
st_line['account_id'] = invoice.account_id.id
1357
st_line['type'] = (invoice.account_id.type == 'receivable') and 'customer' or 'supplier'
1358
iml_ids = move_line_obj.search(cr, uid, [('move_id', '=', invoice.move_id.id), ('reconcile_id', '=', False), ('account_id.reconcile', '=', True)])
1360
st_line['reconcile'] = iml_ids[0]
1362
err_string = _('\nThe CODA parsing detected a database inconsistency while processing movement data record 2.3, seq nr %s!' \
1363
'\nPlease report this issue via your OpenERP support channel.') % line[2:10]
1366
return (err_code, err_string)
1367
raise orm.except_orm(_('Error!'), err_string)
1369
return st_line, coda_parsing_note, match
1371
def _match_counterparty(self, cr, uid, st_line, coda_parsing_note, coda_statement, context=None):
1373
coda_bank_params = coda_statement['coda_bank_params']
1374
transfer_acc = coda_bank_params['transfer_account'][0]
1375
find_partner = coda_bank_params['find_partner']
1376
update_partner = coda_bank_params['update_partner']
1378
partner_bank_obj = self.pool.get('res.partner.bank')
1380
partner_bank_ids = None
1381
counterparty_number = st_line['counterparty_number']
1382
if counterparty_number:
1383
transfer_accounts = filter(lambda x: counterparty_number in x, self.company_bank_accounts)
1384
if transfer_accounts:
1385
if counterparty_number not in _get_acc_numbers(coda_statement['acc_number']): # exclude transactions from counterparty_number = bank account number of this statement
1386
st_line['account_id'] = transfer_acc
1387
match['transfer_account'] = True
1389
partner_bank_ids = partner_bank_obj.search(cr,uid,[('acc_number','=', counterparty_number)])
1390
if not match and find_partner and partner_bank_ids:
1391
partner_banks = partner_bank_obj.browse(cr, uid, partner_bank_ids, context=context)
1392
# filter out partners that belong to other companies
1393
# TO DO : adapt this logic to cope with res.partner record rule customisations
1394
partner_bank_ids2 = []
1395
for pb in partner_banks:
1398
if pb.partner_id.company_id and pb.partner_id.company_id.id != coda_statement['company_id']:
1403
partner_bank_ids2.append(pb.id)
1404
if len(partner_bank_ids2) > 1:
1405
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
1406
"\n No partner record assigned: There are multiple partners with the same Bank Account Number '%s'!") \
1407
% (st_line['ref'], counterparty_number)
1408
elif len(partner_bank_ids2) == 1:
1409
partner_bank = partner_bank_obj.browse(cr, uid, partner_bank_ids2[0], context=context)
1410
st_line['partner_id'] = partner_bank.partner_id.id
1411
match['partner_id'] = st_line['partner_id']
1412
if st_line['amount'] < 0:
1413
st_line['account_id'] = partner_bank.partner_id.property_account_payable.id
1414
st_line['type'] = 'supplier'
1416
st_line['account_id'] = partner_bank.partner_id.property_account_receivable.id
1417
st_line['type'] = 'customer'
1418
elif not match and find_partner:
1419
if counterparty_number:
1420
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
1421
"\n The bank account '%s' is not defined for the partner '%s'!") \
1422
% (st_line['ref'], counterparty_number, st_line['counterparty_name'])
1424
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':" \
1425
"\n No matching partner record found!" \
1426
"\n Please adjust the corresponding entry manually in the generated Bank Statement.") \
1429
# add bank account to partner record
1430
if match and st_line['account_id'] != transfer_acc and counterparty_number and update_partner:
1431
partner_bank_ids = partner_bank_obj.search(cr,uid,[('acc_number','=', counterparty_number), ('partner_id', '=', st_line['partner_id'])], order='id')
1432
if len(partner_bank_ids) > 1:
1433
# clean up partner bank duplicates, keep most recently created
1434
_logger.warn('Duplicate Bank Accounts for partner_id %s have been removed, ids = %s',
1435
st_line['partner_id'], partner_bank_ids[:-1])
1436
partner_bank_obj.unlink(cr,uid, partner_bank_ids[:-1])
1437
if not partner_bank_ids:
1438
feedback = update_partner_bank(self, cr, uid, st_line['counterparty_bic'], counterparty_number, st_line['partner_id'], st_line['counterparty_name'])
1440
coda_parsing_note += _("\n Bank Statement '%%(name)s' line '%s':") % st_line['ref'] + feedback
1442
return st_line, coda_parsing_note, match
1444
def _coda_statement_init(self, cr, uid, coda_statement, coda_note, context=None):
1446
Use this method to take customer specific actions once a specific statement has been identified in a coda file.
1448
coda_statement : e.g. add parameters
1449
coda_note: e.g. add extra info to the CODA Note
1451
return coda_statement, coda_note
1380
1453
def _statement_hook(self, cr, uid, coda_bank_params, st_vals, context=None):
1382
1455
Use this method to take customer specific actions based upon the bank statement data.