Laurent Mignon (Acsone) has proposed merging lp:~acsone-openerp/banking-addons/bank-statement-reconcile-70 into lp:banking-addons/bank-statement-reconcile-7.0.
Requested reviews: Banking Addons Core Editors (banking-addons-team) Related bugs: Bug #1223834 in Banking Addons: "[7.0] account_statement_base_import - AccountStatementLine. _insert_lines the module doesn't handle correctly sparse fields of type 'char' referencing a serialisable field" https://bugs.launchpad.net/banking-addons/+bug/1223834 For more details, see: https://code.launchpad.net/~acsone-openerp/banking-addons/bank-statement-reconcile-70/+merge/185047 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'. What's your opinion? Regards, lmi -- https://code.launchpad.net/~acsone-openerp/banking-addons/bank-statement-reconcile-70/+merge/185047 Your team Banking Addons Core Editors is requested to review the proposed merge of lp:~acsone-openerp/banking-addons/bank-statement-reconcile-70 into lp:banking-addons/bank-statement-reconcile-7.0.
=== added directory 'account_statement_bankaccount_completion' === added file 'account_statement_bankaccount_completion/__init__.py' --- account_statement_bankaccount_completion/__init__.py 1970-01-01 00:00:00 +0000 +++ account_statement_bankaccount_completion/__init__.py 2013-09-11 13:21:05 +0000 @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +# +# +# Author: Laurent Mignon +# Copyright 2013 'ACSONE SA/NV' +# +# 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/>. +# +# +import statement === added file 'account_statement_bankaccount_completion/__openerp__.py' --- account_statement_bankaccount_completion/__openerp__.py 1970-01-01 00:00:00 +0000 +++ account_statement_bankaccount_completion/__openerp__.py 2013-09-11 13:21:05 +0000 @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +# +# +# Author: Laurent Mignon +# Copyright 2013 'ACSONE SA/NV' +# +# 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': "Bank statement completion from bank account number", + 'version': '1.0', + 'author': 'Laurent Mignon (Acsone)', + 'maintainer': 'ACSONE SA/NV', + 'category': 'Finance', + 'complexity': 'normal', + 'depends': [ + 'account_statement_base_completion', + # HACK! the account_statement_base_completion need + # to depend from account_statement_base_import since it use specific method on the + # statement line during completion. (methods are defined in the + # account_statement_base_impor module + 'account_statement_base_import' + ], + 'description': """ + Add a completion method based on the partner bank account number provided by the bank/office. + + Completion will look in the partner with that bank account number to match the partner, + then it will fill in the bank statement line with it to ease the reconciliation. + + """, + 'website': 'http://www.acsone.eu', + 'init_xml': [], + 'update_xml': [ + "data.xml", + ], + 'demo_xml': [], + 'test': [], + 'installable': True, + 'images': [], + 'auto_install': True, + 'license': 'AGPL-3', + } === added file 'account_statement_bankaccount_completion/data.xml' --- account_statement_bankaccount_completion/data.xml 1970-01-01 00:00:00 +0000 +++ account_statement_bankaccount_completion/data.xml 2013-09-11 13:21:05 +0000 @@ -0,0 +1,12 @@ +<?xml version="1.0" encoding="utf-8"?> +<openerp> +<data noupdate="1"> + + <record id="bank_statement_completion_rule_10" model="account.statement.completion.rule"> + <field name="name">Match from bank account number (Nomal or IBAN))</field> + <field name="sequence">10</field> + <field name="function_to_call">get_from_bank_account</field> + </record> + +</data> +</openerp> === added file 'account_statement_bankaccount_completion/statement.py' --- account_statement_bankaccount_completion/statement.py 1970-01-01 00:00:00 +0000 +++ account_statement_bankaccount_completion/statement.py 2013-09-11 13:21:05 +0000 @@ -0,0 +1,96 @@ +# -*- coding: utf-8 -*- +# +# +# Author: Laurent Mignon +# Copyright 2013 'ACSONE SA/NV' +# +# 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.tools.translate import _ +from openerp.osv.orm import Model +from openerp.osv import fields +from openerp.addons.account_statement_base_completion.statement import ErrorTooManyPartner + + +class AccountStatementCompletionRule(Model): + + """Add a rule based on transaction ID""" + + _inherit = "account.statement.completion.rule" + + def _get_functions(self, cr, uid, context=None): + res = super(AccountStatementCompletionRule, self)._get_functions( + cr, uid, context=context) + res.append(('get_from_bank_account', + 'From bank account number (Nomal or IBAN)')) + return res + + _columns = { + 'function_to_call': fields.selection(_get_functions, 'Method'), + } + + def get_from_bank_account(self, cr, uid, st_line, context=None): + """ + Match the partner based on the partner account number field + Then, call the generic st_line method to complete other values. + :param dict st_line: read of the concerned account.bank.statement.line + :return: + A dict of value that can be passed directly to the write method of + the statement line or {} + {'partner_id': value, + 'account_id' : value, + ...} + """ + if st_line['partner_acc_number'] == False: + return {} + st_obj = self.pool.get('account.bank.statement.line') + res = {} + res_bank_obj = self.pool.get('res.partner.bank') + ids = res_bank_obj.search(cr, + uid, + [('acc_number', '=', st_line['partner_acc_number'])], + context=context) + if len(ids) > 1: + raise ErrorTooManyPartner(_('Line named "%s" (Ref:%s) was matched by more than ' + 'one partner.') % (st_line['name'], st_line['ref'])) + if len(ids) == 1: + partner = res_bank_obj.browse(cr, uid, ids[0], context=context).partner_id + res['partner_id'] = partner.id + st_vals = st_obj.get_values_for_line(cr, + uid, + profile_id=st_line['profile_id'], + master_account_id=st_line['master_account_id'], + partner_id=res.get('partner_id', False), + line_type=st_line['type'], + amount=st_line['amount'] if st_line['amount'] else 0.0, + context=context) + res.update(st_vals) + return res + + +class AccountStatementLine(Model): + _inherit = "account.bank.statement.line" + + _columns = { + # 'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', help="Used by completion and import system."), + 'partner_acc_number': fields.sparse( + type='char', + string='Account Number', + size=64, + serialization_field='additionnal_bank_fields', + help="Account number of the partner"), + } === added directory 'account_statement_bankaccount_completion/tests' === added file 'account_statement_bankaccount_completion/tests/__init__.py' --- account_statement_bankaccount_completion/tests/__init__.py 1970-01-01 00:00:00 +0000 +++ account_statement_bankaccount_completion/tests/__init__.py 2013-09-11 13:21:05 +0000 @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# +# Authors: Laurent Mignon +# Copyright (c) 2013 Acsone SA/NV (http://www.acsone.eu) +# 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 . import test_bankaccount_completion + +checks = [ + test_bankaccount_completion +] === added file 'account_statement_bankaccount_completion/tests/test_bankaccount_completion.py' --- account_statement_bankaccount_completion/tests/test_bankaccount_completion.py 1970-01-01 00:00:00 +0000 +++ account_statement_bankaccount_completion/tests/test_bankaccount_completion.py 2013-09-11 13:21:05 +0000 @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# +# +# Authors: Laurent Mignon +# Copyright (c) 2013 Acsone SA/NV (http://www.acsone.eu) +# 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.tests import common +import inspect +import os +import base64 +import time + +ACC_NUMBER = "BE38733040385372" + + +class bankaccount_completion(common.TransactionCase): + + def prepare(self): + self.company_a = self.browse_ref('base.main_company') + self.profile_obj = self.registry("account.statement.profile") + self.account_bank_statement_obj = self.registry("account.bank.statement") + self.account_bank_statement_line_obj = self.registry("account.bank.statement.line") + self.completion_rule_id = self.ref('account_statement_bankaccount_completion.bank_statement_completion_rule_10') + self.journal_id = self.registry("ir.model.data").get_object_reference(self.cr, self. uid, "account", "bank_journal")[1] + self.partner_id = self.ref('base.main_partner') + # Create the profile + self.account_id = self.registry("ir.model.data").get_object_reference(self.cr, self.uid, "account", "a_recv")[1] + self.journal_id = self.registry("ir.model.data").get_object_reference(self.cr, self. uid, "account", "bank_journal")[1] + self.profile_id = self.profile_obj.create(self.cr, self.uid, { + "name": "TEST", + "commission_account_id": self.account_id, + "journal_id": self.journal_id, + "import_type": 'generic_csvxls_so', + "rule_ids": [(6, 0, [self.completion_rule_id])]}) + # Create the completion rule + + # Create a bank statement + self.statement_id = self.account_bank_statement_obj.create(self.cr, self.uid, { + "balance_end_real": 0.0, + "balance_start": 0.0, + "date": time.strftime('%Y-%m-%d'), + "journal_id": self.journal_id, + "profile_id": self.profile_id + + }) + + # Create bank a statement line + self.statement_line_id = self.account_bank_statement_line_obj.create(self.cr, self.uid, { + 'amount': 1000.0, + 'name': 'EXT001', + 'ref': 'My ref', + 'statement_id': self.statement_id, + 'partner_acc_number': ACC_NUMBER + }) + + # Add a bank account number to the partner + res_bank_obj = self.registry('res.partner.bank') + res_bank_id = res_bank_obj.create(self.cr, self.uid, { + "state": "bank", + "company_id": self.company_a.id, + "partner_id": self.partner_id, + "acc_number": ACC_NUMBER, + "footer": True, + "bank_name": "Reserve" + }) + + def test_OO(self): + """Test complete partner_id from bank account number + + Test the automatic completion of the partner_id based on the account number associated to the + statement line + """ + self.prepare() + statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line_id) + # before import, the + self.assertFalse(statement_line.partner_id, "Partner_id must be blank before completion") + statement_obj = self.account_bank_statement_obj.browse(self.cr, self.uid, self.statement_id) + statement_obj.button_auto_completion() + statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line_id) + self.assertEquals(self.partner_id, statement_line.partner_id['id'], "Missing expected partner id after completion") === modified file 'account_statement_base_import/statement.py' --- account_statement_base_import/statement.py 2013-05-03 19:57:26 +0000 +++ account_statement_base_import/statement.py 2013-09-11 13:21:05 +0000 @@ -28,6 +28,7 @@ from openerp.osv.orm import Model from openerp.osv import fields, osv from parser import new_bank_statement_parser +import simplejson class AccountStatementProfil(Model): @@ -225,14 +226,40 @@ """ _inherit = "account.bank.statement.line" - def _get_available_columns(self, statement_store): + def _get_available_columns(self, statement_store, include_serializable=False): """Return writeable by SQL columns""" statement_line_obj = self.pool['account.bank.statement.line'] model_cols = statement_line_obj._columns avail = [k for k, col in model_cols.iteritems() if not hasattr(col, '_fnct')] keys = [k for k in statement_store[0].keys() if k in avail] + # add sparse fields.. + if include_serializable: + for k, col in model_cols.iteritems(): + if k in statement_store[0].keys() and \ + isinstance(col, fields.sparse) and \ + col.serialization_field not in keys and \ + col._type == 'char': + keys.append(col.serialization_field) keys.sort() return keys + + def _get_values(self, cols, statement_store): + statement_line_obj = self.pool['account.bank.statement.line'] + model_cols = statement_line_obj._columns + sparse_fields = dict([(k , col) for k, col in model_cols.iteritems() if isinstance(col, fields.sparse) and col._type == 'char']) + values = [] + for statement in statement_store: + to_json_k = set() + for k, col in sparse_fields.iteritems(): + if k in statement: + to_json_k.add(col.serialization_field) + serialized = statement.setdefault(col.serialization_field, {}) + serialized[k] = statement[k] + for k in to_json_k: + statement[k] = simplejson.dumps(statement[k]) + values.append(statement) + return values + def _insert_lines(self, cr, uid, statement_store, context=None): """ Do raw insert into database because ORM is awfully slow @@ -241,11 +268,11 @@ statement_line_obj = self.pool['account.bank.statement.line'] statement_line_obj.check_access_rule(cr, uid, [], 'create') statement_line_obj.check_access_rights(cr, uid, 'create', raise_exception=True) - cols = self._get_available_columns(statement_store) + cols = self._get_available_columns(statement_store, include_serializable=True) tmp_vals = (', '.join(cols), ', '.join(['%%(%s)s' % i for i in cols])) sql = "INSERT INTO account_bank_statement_line (%s) VALUES (%s);" % tmp_vals try: - cr.executemany(sql, tuple(statement_store)) + cr.executemany(sql, tuple(self._get_values(cols, statement_store))) except psycopg2.Error as sql_err: cr.rollback() raise osv.except_osv(_("ORM bypass error"), === modified file 'account_statement_ext/statement.py' --- account_statement_ext/statement.py 2013-05-24 09:38:35 +0000 +++ account_statement_ext/statement.py 2013-09-11 13:21:05 +0000 @@ -553,7 +553,11 @@ if context is None: context = {} date = context.get('date') - periods = self.pool.get('account.period').find(cr, uid, dt=date) + try: + periods = self.pool.get('account.period').find(cr, uid, dt=date) + except osv.except_osv: + # if no period defined, we are certainly at installation time + return False return periods and periods[0] or False def _get_default_account(self, cr, uid, context=None): === modified file 'account_statement_transactionid_completion/statement.py' --- account_statement_transactionid_completion/statement.py 2013-04-25 11:30:23 +0000 +++ account_statement_transactionid_completion/statement.py 2013-09-11 13:21:05 +0000 @@ -90,5 +90,5 @@ string='Transaction ID', size=128, serialization_field='additionnal_bank_fields', - help="Transction id from the financial institute"), + help="Transaction id from the financial institute"), }
-- Mailing list: https://launchpad.net/~banking-addons-team Post to : [email protected] Unsubscribe : https://launchpad.net/~banking-addons-team More help : https://help.launchpad.net/ListHelp

