~akretion-team/banking-addons/bank-statement-reconcile-70-api-improvement

« back to all changes in this revision

Viewing changes to account_statement_base_completion/statement.py

  • Committer: Joel Grand-Guillaume
  • Author(s): Laurent Mignon (Acsone)
  • Date: 2013-10-16 08:58:12 UTC
  • mfrom: (94.1.21 addons-banking)
  • Revision ID: joel.grandguillaume@camptocamp.com-20131016085812-1fm2rwdopzvr68zu
[IMP] Fixes lp:1223834 in case of insert. Batch updates remains error prone. It would be safer to call the update method from the orm for records updating 'complex' fields.

A new completion rule based on the bank account number is also provided by the proposal.

About modules dependencies. The module 'account_statement_base_import' depends of 'account_statement_base_completion' but the file statement.py of 'account_statement_base_completion' at line 513 call the method _update_line defined in 'account_statement_base_import'. Since the 'AccountStatementLine' is defined in both addons, I've the feeling that we can merge the two overrides in 'account_statement_base_completion'.

Show diffs side-by-side

added added

removed removed

Lines of Context:
22
22
import traceback
23
23
import sys
24
24
import logging
 
25
import simplejson
 
26
 
 
27
import psycopg2
25
28
 
26
29
from collections import defaultdict
27
30
import re
433
436
            return vals
434
437
        return {}
435
438
 
 
439
    def _get_available_columns(self, statement_store, include_serializable=False):
 
440
        """Return writeable by SQL columns"""
 
441
        statement_line_obj = self.pool['account.bank.statement.line']
 
442
        model_cols = statement_line_obj._columns
 
443
        avail = [k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct')]
 
444
        keys = [k for k in statement_store[0].keys() if k in avail]
 
445
        # add sparse fields..
 
446
        if include_serializable:
 
447
            for k, col in model_cols.iteritems():
 
448
                if  k in statement_store[0].keys() and \
 
449
                      isinstance(col, fields.sparse) and \
 
450
                      col.serialization_field not in keys and \
 
451
                      col._type == 'char':
 
452
                    keys.append(col.serialization_field)
 
453
        keys.sort()
 
454
        return keys
 
455
 
 
456
    def _serialize_sparse_fields(self, cols, statement_store):
 
457
        """ Serialize sparse fields values in the target serialized field
 
458
        Return a copy of statement_store
 
459
        """
 
460
        statement_line_obj = self.pool['account.bank.statement.line']
 
461
        model_cols = statement_line_obj._columns
 
462
        sparse_fields = dict([(k , col) for k, col in model_cols.iteritems() if isinstance(col, fields.sparse) and col._type == 'char'])
 
463
        values = []
 
464
        for statement in statement_store:
 
465
            to_json_k = set()
 
466
            st_copy = statement.copy()
 
467
            for k, col in sparse_fields.iteritems():
 
468
                if k in st_copy:
 
469
                    to_json_k.add(col.serialization_field)
 
470
                    serialized = st_copy.setdefault(col.serialization_field, {})
 
471
                    serialized[k] = st_copy[k]
 
472
            for k in to_json_k:
 
473
                st_copy[k] =  simplejson.dumps(st_copy[k])
 
474
            values.append(st_copy)
 
475
        return values
 
476
        
 
477
 
 
478
    def _insert_lines(self, cr, uid, statement_store, context=None):
 
479
        """ Do raw insert into database because ORM is awfully slow
 
480
            when doing batch write. It is a shame that batch function
 
481
            does not exist"""
 
482
        statement_line_obj = self.pool['account.bank.statement.line']
 
483
        statement_line_obj.check_access_rule(cr, uid, [], 'create')
 
484
        statement_line_obj.check_access_rights(cr, uid, 'create', raise_exception=True)
 
485
        cols = self._get_available_columns(statement_store, include_serializable=True)
 
486
        tmp_vals = (', '.join(cols), ', '.join(['%%(%s)s' % i for i in cols]))
 
487
        sql = "INSERT INTO account_bank_statement_line (%s) VALUES (%s);" % tmp_vals
 
488
        try:
 
489
            cr.executemany(sql, tuple(self._serialize_sparse_fields(cols, statement_store)))
 
490
        except psycopg2.Error as sql_err:
 
491
            cr.rollback()
 
492
            raise osv.except_osv(_("ORM bypass error"),
 
493
                                 sql_err.pgerror)
 
494
 
 
495
    def _update_line(self, cr, uid, vals, context=None):
 
496
        """ Do raw update into database because ORM is awfully slow
 
497
            when cheking security.
 
498
        TODO / WARM: sparse fields are skipped by the method. IOW, if your
 
499
        completion rule update an sparse field, the updated value will never
 
500
        be stored in the database. It would be safer to call the update method 
 
501
        from the ORM for records updating this kind of fields.
 
502
        """
 
503
        cols = self._get_available_columns([vals])
 
504
        tmp_vals = (', '.join(['%s = %%(%s)s' % (i, i) for i in cols]))
 
505
        sql = "UPDATE account_bank_statement_line SET %s where id = %%(id)s;" % tmp_vals
 
506
        try:
 
507
            cr.execute(sql, vals)
 
508
        except psycopg2.Error as sql_err:
 
509
            cr.rollback()
 
510
            raise osv.except_osv(_("ORM bypass error"),
 
511
                                 sql_err.pgerror)
 
512
 
436
513
 
437
514
class AccountBankSatement(orm.Model):
438
515
    """