From d8e7cb77a216bcfbc04030e6eb2bff19cdf1485e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=ABl=20Grand-Guillaume?= Date: Wed, 6 Jun 2012 16:27:25 +0200 Subject: [PATCH] [MRG] From customer branch (lp:c2c-financial-addons/6.1 rev 58) --- account_advanced_reconcile/__init__.py | 24 - account_advanced_reconcile/__openerp__.py | 90 ---- .../advanced_reconciliation.py | 120 ----- .../base_advanced_reconciliation.py | 274 ----------- account_advanced_reconcile/easy_reconcile.py | 37 -- .../easy_reconcile_view.xml | 20 - account_statement_base_completion/__init__.py | 22 - .../__openerp__.py | 70 --- account_statement_base_completion/data.xml | 32 -- account_statement_base_completion/partner.py | 38 -- .../partner_view.xml | 22 - .../statement.py | 361 -------------- .../statement_view.xml | 88 ---- account_statement_base_import/__init__.py | 23 - account_statement_base_import/__openerp__.py | 68 --- .../datas/statement.csv | 4 - .../datas/statement.xls | Bin 6656 -> 0 bytes .../parser/__init__.py | 25 - .../parser/file_parser.py | 176 ------- .../parser/generic_file_parser.py | 102 ---- .../parser/parser.py | 213 --------- account_statement_base_import/statement.py | 233 ---------- .../statement_view.xml | 43 -- .../wizard/__init__.py | 20 - .../wizard/import_statement.py | 115 ----- .../wizard/import_statement_view.xml | 44 -- account_statement_ext/__init__.py | 4 +- account_statement_ext/__openerp__.py | 48 +- account_statement_ext/account.py | 40 -- account_statement_ext/report.xml | 25 - account_statement_ext/report/__init__.py | 31 -- .../report/bank_statement_report.mako | 69 --- .../report/bank_statement_report.py | 70 --- .../report/bank_statement_webkit_header.xml | 180 ------- account_statement_ext/statement.py | 440 ++---------------- account_statement_ext/statement_view.xml | 211 ++------- account_statement_ext_voucher/__init__.py | 22 - account_statement_ext_voucher/__openerp__.py | 43 -- .../statement_voucher.py | 41 -- .../__init__.py | 22 - .../__openerp__.py | 52 --- .../data.xml | 12 - .../statement.py | 90 ---- .../statement_view.xml | 22 - .../__init__.py | 21 - .../__openerp__.py | 60 --- .../datas/statement.csv | 4 - .../datas/statement.xls | Bin 6656 -> 0 bytes .../parser/__init__.py | 24 - .../parser/transactionid_file_parser.py | 99 ---- base_transaction_id/__openerp__.py | 10 +- 51 files changed, 89 insertions(+), 3815 deletions(-) delete mode 100644 account_advanced_reconcile/__init__.py delete mode 100644 account_advanced_reconcile/__openerp__.py delete mode 100644 account_advanced_reconcile/advanced_reconciliation.py delete mode 100644 account_advanced_reconcile/base_advanced_reconciliation.py delete mode 100644 account_advanced_reconcile/easy_reconcile.py delete mode 100644 account_advanced_reconcile/easy_reconcile_view.xml delete mode 100644 account_statement_base_completion/__init__.py delete mode 100644 account_statement_base_completion/__openerp__.py delete mode 100644 account_statement_base_completion/data.xml delete mode 100644 account_statement_base_completion/partner.py delete mode 100644 account_statement_base_completion/partner_view.xml delete mode 100644 account_statement_base_completion/statement.py delete mode 100644 account_statement_base_completion/statement_view.xml delete mode 100644 account_statement_base_import/__init__.py delete mode 100644 account_statement_base_import/__openerp__.py delete mode 100644 account_statement_base_import/datas/statement.csv delete mode 100644 account_statement_base_import/datas/statement.xls delete mode 100644 account_statement_base_import/parser/__init__.py delete mode 100644 account_statement_base_import/parser/file_parser.py delete mode 100644 account_statement_base_import/parser/generic_file_parser.py delete mode 100644 account_statement_base_import/parser/parser.py delete mode 100644 account_statement_base_import/statement.py delete mode 100644 account_statement_base_import/statement_view.xml delete mode 100644 account_statement_base_import/wizard/__init__.py delete mode 100644 account_statement_base_import/wizard/import_statement.py delete mode 100644 account_statement_base_import/wizard/import_statement_view.xml delete mode 100644 account_statement_ext/account.py delete mode 100644 account_statement_ext/report.xml delete mode 100644 account_statement_ext/report/__init__.py delete mode 100644 account_statement_ext/report/bank_statement_report.mako delete mode 100644 account_statement_ext/report/bank_statement_report.py delete mode 100644 account_statement_ext/report/bank_statement_webkit_header.xml delete mode 100644 account_statement_ext_voucher/__init__.py delete mode 100644 account_statement_ext_voucher/__openerp__.py delete mode 100644 account_statement_ext_voucher/statement_voucher.py delete mode 100644 account_statement_transactionid_completion/__init__.py delete mode 100644 account_statement_transactionid_completion/__openerp__.py delete mode 100644 account_statement_transactionid_completion/data.xml delete mode 100644 account_statement_transactionid_completion/statement.py delete mode 100644 account_statement_transactionid_completion/statement_view.xml delete mode 100644 account_statement_transactionid_import/__init__.py delete mode 100644 account_statement_transactionid_import/__openerp__.py delete mode 100644 account_statement_transactionid_import/datas/statement.csv delete mode 100644 account_statement_transactionid_import/datas/statement.xls delete mode 100644 account_statement_transactionid_import/parser/__init__.py delete mode 100644 account_statement_transactionid_import/parser/transactionid_file_parser.py diff --git a/account_advanced_reconcile/__init__.py b/account_advanced_reconcile/__init__.py deleted file mode 100644 index 1c643cae..00000000 --- a/account_advanced_reconcile/__init__.py +++ /dev/null @@ -1,24 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Guewen Baconnier -# Copyright 2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -import easy_reconcile -import base_advanced_reconciliation -import advanced_reconciliation diff --git a/account_advanced_reconcile/__openerp__.py b/account_advanced_reconcile/__openerp__.py deleted file mode 100644 index 5ca17767..00000000 --- a/account_advanced_reconcile/__openerp__.py +++ /dev/null @@ -1,90 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Guewen Baconnier -# Copyright 2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -{'name': "Advanced Reconcile", - 'version': '1.0', - 'author': 'Camptocamp', - 'maintainer': 'Camptocamp', - 'category': 'Finance', - 'complexity': 'normal', - 'depends': ['account_easy_reconcile'], - 'description': """ -Advanced reconciliation methods for the module account_easy_reconcile. - -account_easy_reconcile, which is a dependency, is available in the branch: -lp:~openerp-community-committers/+junk/account-extra-addons -This branch is temporary and will soon be merged with the Akretion master -branch, but the master branch does not already exist. Sorry for the -inconvenience. - -In addition to the features implemented in account_easy_reconcile, which are: - - reconciliation facilities for big volume of transactions - - setup different profiles of reconciliation by account - - each profile can use many methods of reconciliation - - this module is also a base to create others reconciliation methods - which can plug in the profiles - - a profile a reconciliation can be run manually or by a cron - - monitoring of reconcilation runs with a few logs - -It implements a basis to created advanced reconciliation methods in a few lines -of code. - -Typically, such a method can be: - - Reconcile entries if the partner and the ref are equal - - Reconcile entries if the partner is equal and the ref is the same than ref - or name - - Reconcile entries if the partner is equal and the ref match with a pattern - -And they allows: - - Reconciliations with multiple credit / multiple debit lines - - Partial reconciliations - - Write-off amount as well - -A method is already implemented in this module, it matches on entries: - * Partner - * Ref on credit move lines should be case insensitive equals to the ref or - the name of the debit move line - -The base class to find the reconciliations is built to be as efficient as -possible. - - -So basically, if you have an invoice with 3 payments (one per month), the first -month, it will partial reconcile the debit move line with the first payment, the second -month, it will partial reconcile the debit move line with 2 first payments, -the third month, it will make the full reconciliation. - -This module is perfectly adapted for E-Commerce business where a big volume of -move lines and so, reconciliations, are involved and payments often come from -many offices. - - """, - 'website': 'http://www.camptocamp.com', - 'init_xml': [], - 'update_xml': ['easy_reconcile_view.xml'], - 'demo_xml': [], - 'test': [], - 'images': [], - 'installable': True, - 'auto_install': False, - 'license': 'AGPL-3', - 'application': True, -} diff --git a/account_advanced_reconcile/advanced_reconciliation.py b/account_advanced_reconcile/advanced_reconciliation.py deleted file mode 100644 index dfdb8883..00000000 --- a/account_advanced_reconcile/advanced_reconciliation.py +++ /dev/null @@ -1,120 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Guewen Baconnier -# Copyright 2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -from openerp.osv.orm import TransientModel - - -class easy_reconcile_advanced_ref(TransientModel): - - _name = 'easy.reconcile.advanced.ref' - _inherit = 'easy.reconcile.advanced' - _auto = True # False when inherited from AbstractModel - - def _skip_line(self, cr, uid, rec, move_line, context=None): - """ - When True is returned on some conditions, the credit move line - will be skipped for reconciliation. Can be inherited to - skip on some conditions. ie: ref or partner_id is empty. - """ - return not (move_line.get('ref') and move_line.get('partner_id')) - - def _matchers(self, cr, uid, rec, move_line, context=None): - """ - Return the values used as matchers to found the opposite lines - - All the matcher keys in the dict must have their equivalent in - the `_opposite_matchers`. - - The values of each matcher key will be searched in the - one returned by the `_opposite_matchers` - - Must be inherited to implement the matchers for one method - - As instance, it can returns: - return ('ref', move_line['rec']) - - or - return (('partner_id', move_line['partner_id']), - ('ref', "prefix_%s" % move_line['rec'])) - - All the matchers have to be found in the opposite lines - to consider them as "opposite" - - The matchers will be evaluated in the same order than declared - vs the the opposite matchers, so you can gain performance by - declaring first the partners with the less computation. - - All matchers should match with their opposite to be considered - as "matching". - So with the previous example, partner_id and ref have to be - equals on the opposite line matchers. - - :return: tuple of tuples (key, value) where the keys are - the matchers keys - (must be the same than `_opposite_matchers` returns, - and their values to match in the opposite lines. - A matching key can have multiples values. - """ - return (('partner_id', move_line['partner_id']), - ('ref', move_line['ref'].lower().strip())) - - def _opposite_matchers(self, cr, uid, rec, move_line, context=None): - """ - Return the values of the opposite line used as matchers - so the line is matched - - Must be inherited to implement the matchers for one method - It can be inherited to apply some formatting of fields - (strip(), lower() and so on) - - This method is the counterpart of the `_matchers()` method. - - Each matcher have to yield its value respecting the orders - of the `_matchers()`. - - When a matcher does not correspond, the next matchers won't - be evaluated so the ones which need the less computation - have to be executed first. - - If the `_matchers()` returns: - (('partner_id', move_line['partner_id']), - ('ref', move_line['ref'])) - - Here, you should yield : - yield ('partner_id', move_line['partner_id']) - yield ('ref', move_line['ref']) - - Note that a matcher can contain multiple values, as instance, - if for a move line, you want to search from its `ref` in the - `ref` or `name` fields of the opposite move lines, you have to - yield ('partner_id', move_line['partner_id']) - yield ('ref', (move_line['ref'], move_line['name']) - - An OR is used between the values for the same key. - An AND is used between the differents keys. - - :param dict move_line: values of the move_line - :yield: matchers as tuple ('matcher key', value(s)) - """ - yield ('partner_id', move_line['partner_id']) - yield ('ref', (move_line['ref'].lower().strip(), - move_line['name'].lower().strip())) - diff --git a/account_advanced_reconcile/base_advanced_reconciliation.py b/account_advanced_reconcile/base_advanced_reconciliation.py deleted file mode 100644 index df26708c..00000000 --- a/account_advanced_reconcile/base_advanced_reconciliation.py +++ /dev/null @@ -1,274 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Guewen Baconnier -# Copyright 2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -from itertools import groupby, product -from operator import itemgetter -from openerp.osv.orm import Model, AbstractModel, TransientModel -from openerp.osv import fields - - -class easy_reconcile_advanced(AbstractModel): - - _name = 'easy.reconcile.advanced' - _inherit = 'easy.reconcile.base' - - def _query_debit(self, cr, uid, rec, context=None): - """Select all move (debit>0) as candidate. Optional choice on invoice - will filter with an inner join on the related moves. - """ - select = self._select(rec) - sql_from = self._from(rec) - where, params = self._where(rec) - where += " AND account_move_line.debit > 0 " - - where2, params2 = self._get_filter(cr, uid, rec, context=context) - - query = ' '.join((select, sql_from, where, where2)) - - cr.execute(query, params + params2) - return cr.dictfetchall() - - def _query_credit(self, cr, uid, rec, context=None): - """Select all move (credit>0) as candidate. Optional choice on invoice - will filter with an inner join on the related moves. - """ - select = self._select(rec) - sql_from = self._from(rec) - where, params = self._where(rec) - where += " AND account_move_line.credit > 0 " - - where2, params2 = self._get_filter(cr, uid, rec, context=context) - - query = ' '.join((select, sql_from, where, where2)) - - cr.execute(query, params + params2) - return cr.dictfetchall() - - def _matchers(self, cr, uid, rec, move_line, context=None): - """ - Return the values used as matchers to found the opposite lines - - All the matcher keys in the dict must have their equivalent in - the `_opposite_matchers`. - - The values of each matcher key will be searched in the - one returned by the `_opposite_matchers` - - Must be inherited to implement the matchers for one method - - As instance, it can returns: - return ('ref', move_line['rec']) - - or - return (('partner_id', move_line['partner_id']), - ('ref', "prefix_%s" % move_line['rec'])) - - All the matchers have to be found in the opposite lines - to consider them as "opposite" - - The matchers will be evaluated in the same order than declared - vs the the opposite matchers, so you can gain performance by - declaring first the partners with the less computation. - - All matchers should match with their opposite to be considered - as "matching". - So with the previous example, partner_id and ref have to be - equals on the opposite line matchers. - - :return: tuple of tuples (key, value) where the keys are - the matchers keys - (must be the same than `_opposite_matchers` returns, - and their values to match in the opposite lines. - A matching key can have multiples values. - """ - raise NotImplementedError - - def _opposite_matchers(self, cr, uid, rec, move_line, context=None): - """ - Return the values of the opposite line used as matchers - so the line is matched - - Must be inherited to implement the matchers for one method - It can be inherited to apply some formatting of fields - (strip(), lower() and so on) - - This method is the counterpart of the `_matchers()` method. - - Each matcher have to yield its value respecting the orders - of the `_matchers()`. - - When a matcher does not correspond, the next matchers won't - be evaluated so the ones which need the less computation - have to be executed first. - - If the `_matchers()` returns: - (('partner_id', move_line['partner_id']), - ('ref', move_line['ref'])) - - Here, you should yield : - yield ('partner_id', move_line['partner_id']) - yield ('ref', move_line['ref']) - - Note that a matcher can contain multiple values, as instance, - if for a move line, you want to search from its `ref` in the - `ref` or `name` fields of the opposite move lines, you have to - yield ('partner_id', move_line['partner_id']) - yield ('ref', (move_line['ref'], move_line['name']) - - An OR is used between the values for the same key. - An AND is used between the differents keys. - - :param dict move_line: values of the move_line - :yield: matchers as tuple ('matcher key', value(s)) - """ - raise NotImplementedError - - @staticmethod - def _compare_values(key, value, opposite_value): - """Can be inherited to modify the equality condition - specifically according to the matcher key (maybe using - a like operator instead of equality on 'ref' as instance) - """ - # consider that empty vals are not valid matchers - # it can still be inherited for some special cases - # where it would be allowed - if not (value and opposite_value): - return False - - if value == opposite_value: - return True - return False - - @staticmethod - def _compare_matcher_values(key, values, opposite_values): - """ Compare every values from a matcher vs an opposite matcher - and return True if it matches - """ - for value, ovalue in product(values, opposite_values): - # we do not need to compare all values, if one matches - # we are done - if easy_reconcile_advanced._compare_values(key, value, ovalue): - return True - return False - - @staticmethod - def _compare_matchers(matcher, opposite_matcher): - """ - Prepare and check the matchers to compare - """ - mkey, mvalue = matcher - omkey, omvalue = opposite_matcher - assert mkey == omkey, "A matcher %s is compared with a matcher %s, " \ - " the _matchers and _opposite_matchers are probably wrong" % \ - (mkey, omkey) - if not isinstance(mvalue, (list, tuple)): - mvalue = mvalue, - if not isinstance(omvalue, (list, tuple)): - omvalue = omvalue, - return easy_reconcile_advanced._compare_matcher_values(mkey, mvalue, omvalue) - - def _compare_opposite(self, cr, uid, rec, move_line, opposite_move_line, - matchers, context=None): - opp_matchers = self._opposite_matchers(cr, uid, rec, opposite_move_line, - context=context) - for matcher in matchers: - try: - opp_matcher = opp_matchers.next() - except StopIteration: - # if you fall here, you probably missed to put a `yield` - # in `_opposite_matchers()` - raise ValueError("Missing _opposite_matcher: %s" % matcher[0]) - - if not self._compare_matchers(matcher, opp_matcher): - # if any of the matcher fails, the opposite line - # is not a valid counterpart - # directly returns so the next yield of _opposite_matchers - # are not evaluated - return False - - return True - - def _search_opposites(self, cr, uid, rec, move_line, opposite_move_lines, context=None): - """ - Search the opposite move lines for a move line - - :param dict move_line: the move line for which we search opposites - :param list opposite_move_lines: list of dict of move lines values, the move - lines we want to search for - :return: list of matching lines - """ - matchers = self._matchers(cr, uid, rec, move_line, context=context) - return [op for op in opposite_move_lines if \ - self._compare_opposite(cr, uid, rec, move_line, op, matchers, context=context)] - - def _action_rec(self, cr, uid, rec, context=None): - credit_lines = self._query_credit(cr, uid, rec, context=context) - debit_lines = self._query_debit(cr, uid, rec, context=context) - return self._rec_auto_lines_advanced( - cr, uid, rec, credit_lines, debit_lines, context=context) - - def _skip_line(self, cr, uid, rec, move_line, context=None): - """ - When True is returned on some conditions, the credit move line - will be skipped for reconciliation. Can be inherited to - skip on some conditions. ie: ref or partner_id is empty. - """ - return False - - def _rec_auto_lines_advanced(self, cr, uid, rec, credit_lines, debit_lines, context=None): - if context is None: - context = {} - - reconciled_ids = [] - partial_reconciled_ids = [] - reconcile_groups = [] - - for credit_line in credit_lines: - if self._skip_line(cr, uid, rec, credit_line, context=context): - continue - - opposite_lines = self._search_opposites( - cr, uid, rec, credit_line, debit_lines, context=context) - - if not opposite_lines: - continue - - opposite_ids = [l['id'] for l in opposite_lines] - line_ids = opposite_ids + [credit_line['id']] - for group in reconcile_groups: - if any([lid in group for lid in opposite_ids]): - group.update(line_ids) - break - else: - reconcile_groups.append(set(line_ids)) - - lines_by_id = dict([(l['id'], l) for l in credit_lines + debit_lines]) - for reconcile_group_ids in reconcile_groups: - group_lines = [lines_by_id[lid] for lid in reconcile_group_ids] - reconciled, full = self._reconcile_lines( - cr, uid, rec, group_lines, allow_partial=True, context=context) - if reconciled and full: - reconciled_ids += reconcile_group_ids - elif reconciled: - partial_reconciled_ids += reconcile_group_ids - - return reconciled_ids, partial_reconciled_ids - diff --git a/account_advanced_reconcile/easy_reconcile.py b/account_advanced_reconcile/easy_reconcile.py deleted file mode 100644 index 747a2e3c..00000000 --- a/account_advanced_reconcile/easy_reconcile.py +++ /dev/null @@ -1,37 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Guewen Baconnier -# Copyright 2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -from openerp.osv.orm import Model - - -class account_easy_reconcile_method(Model): - - _inherit = 'account.easy.reconcile.method' - - def _get_all_rec_method(self, cr, uid, context=None): - methods = super(account_easy_reconcile_method, self).\ - _get_all_rec_method(cr, uid, context=context) - methods += [ - ('easy.reconcile.advanced.ref', - 'Advanced. Partner and Ref.'), - ] - return methods - diff --git a/account_advanced_reconcile/easy_reconcile_view.xml b/account_advanced_reconcile/easy_reconcile_view.xml deleted file mode 100644 index 961add68..00000000 --- a/account_advanced_reconcile/easy_reconcile_view.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - account.easy.reconcile.form - account.easy.reconcile - form - - - - - - - - - - - diff --git a/account_statement_base_completion/__init__.py b/account_statement_base_completion/__init__.py deleted file mode 100644 index f6c46966..00000000 --- a/account_statement_base_completion/__init__.py +++ /dev/null @@ -1,22 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Joel Grand-Guillaume -# Copyright 2011-2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -import statement \ No newline at end of file diff --git a/account_statement_base_completion/__openerp__.py b/account_statement_base_completion/__openerp__.py deleted file mode 100644 index d9f61447..00000000 --- a/account_statement_base_completion/__openerp__.py +++ /dev/null @@ -1,70 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Joel Grand-Guillaume -# Copyright 2011-2012 Camptocamp SA -# -# 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 . -# -############################################################################## - -{'name': "Bank statement base completion", - 'version': '1.0', - 'author': 'Camptocamp', - 'maintainer': 'Camptocamp', - 'category': 'Finance', - 'complexity': 'normal', #easy, normal, expert - 'depends': ['account_statement_ext'], - 'description': """ - The goal of this module is to improve the basic bank statement, help dealing with huge volume of - reconciliation by providing basic rules to identify the partner of a bank statement line. - Each bank statement profile can have his own rules to apply respecting a sequence order. - - Some basic rules are provided in this module: - - 1) Match from statement line label (based on partner field 'Bank Statement Label') - 2) Match from statement line label (based on partner name) - 3) Match from statement line reference (based on SO number) - 3) Match from statement line reference (based on Invoice number) - - You can easily override this module and add your own rules in your own one. The basic rules only - fullfill the partner, but you can use them to complete all values of the line (in the future, we'll - add rule to automatically match and reconcile the line). - - It add as well a label on the bank statement line (on which the pre-define rules can match) and - a char field on the partner called 'Bank Statement Label'. Using the pre-define rules, you'll be - able to match various label for a partner. - - The reference of the line is always used by the reconciliation process. We're supposed to copy - there (or write manually) the matching string. That can be : the order Number or an invoice number, - or anything that will be found in the invoice accounting entry part to make the match. - - You can use it with our account_advanced_reconcile module to automatize the reconciliation process. - - """, - 'website': 'http://www.camptocamp.com', - 'init_xml': [], - 'update_xml': [ - 'statement_view.xml', - 'partner_view.xml', - 'data.xml', - ], - 'demo_xml': [], - 'test': [], - 'installable': True, - 'images': [], - 'auto_install': False, - 'license': 'AGPL-3', - 'active': False, -} diff --git a/account_statement_base_completion/data.xml b/account_statement_base_completion/data.xml deleted file mode 100644 index 3757e4fd..00000000 --- a/account_statement_base_completion/data.xml +++ /dev/null @@ -1,32 +0,0 @@ - - - - - - Match from line label (based on partner field 'Bank Statement Label') - 60 - get_from_label_and_partner_field - - - - Match from line label (based on partner name) - 70 - get_from_label_and_partner_name - - - - Match from line reference (based on SO number) - 50 - get_from_ref_and_so - - - - Match from line reference (based on Invoice number) - 40 - get_from_ref_and_invoice - - - - - - diff --git a/account_statement_base_completion/partner.py b/account_statement_base_completion/partner.py deleted file mode 100644 index 978de421..00000000 --- a/account_statement_base_completion/partner.py +++ /dev/null @@ -1,38 +0,0 @@ -# -*- encoding: utf-8 -*- -################################################################################# -# # -# Copyright (C) 2011 Akretion & Camptocamp -# Author : Sébastien BEAU, Joel Grand-Guillaume # -# # -# 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 . # -# # -################################################################################# - -from osv import fields, osv - -class res_partner(osv.osv): - """ - Add a bank label on the partner so that we can use it to match - this partner when we found this in a statement line. - """ - _inherit = 'res.partner' - - _columns = { - 'bank_statement_label':fields.char('Bank Statement Label', size=100, - help="Enter the various label found on your bank statement separated by a ; If \ - one of this label is include in the bank statement line, the partner will be automatically \ - filled (as long as you use this method/rules in your statement profile)."), - } - -res_partner() diff --git a/account_statement_base_completion/partner_view.xml b/account_statement_base_completion/partner_view.xml deleted file mode 100644 index c7ec3f1a..00000000 --- a/account_statement_base_completion/partner_view.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - - account_bank_statement_import.view.partner.form - res.partner - form - 20 - - - - - - - - - - - diff --git a/account_statement_base_completion/statement.py b/account_statement_base_completion/statement.py deleted file mode 100644 index 551707ac..00000000 --- a/account_statement_base_completion/statement.py +++ /dev/null @@ -1,361 +0,0 @@ -# -*- coding: utf-8 -*- -############################################################################## -# -# Author: Nicolas Bessi, Joel Grand-Guillaume -# Copyright 2011-2012 Camptocamp SA -# -# 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 . -# -############################################################################## -from tools.translate import _ -import netsvc -logger = netsvc.Logger() -from openerp.osv.orm import Model, fields -from openerp.osv import fields, osv -from operator import itemgetter, attrgetter - -class ErrorTooManyPartner(Exception): - """ - New Exception definition that is raised when more than one partner is matched by - the completion rule. - """ - def __init__(self, value): - self.value = value - def __str__(self): - return repr(self.value) - - -class AccountStatementProfil(Model): - """ - Extend the class to add rules per profil that will match at least the partner, - but it could also be used to match other values as well. - """ - - _inherit = "account.statement.profil" - - _columns={ - # @Akretion : For now, we don't implement this features, but this would probably be there: - # 'auto_completion': fields.text('Auto Completion'), - # 'transferts_account_id':fields.many2one('account.account', 'Transferts Account'), - # => You can implement it in a module easily, we design it with your needs in mind - # as well ! - - 'rule_ids':fields.many2many('account.statement.completion.rule', - string='Related statement profiles', - rel='as_rul_st_prof_rel', - ), - } - - def find_values_from_rules(self, cr, uid, id, line_id, context=None): - """ - This method will execute all related rules, in their sequence order, - to retrieve all the values returned by the first rules that will match. - - :param int/long line_id: id 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 not context: - context={} - res = {} - rule_obj = self.pool.get('account.statement.completion.rule') - profile = self.browse(cr, uid, id, context=context) - # We need to respect the sequence order - sorted_array = sorted(profile.rule_ids, key=attrgetter('sequence')) - for rule in sorted_array: - method_to_call = getattr(rule_obj, rule.function_to_call) - result = method_to_call(cr,uid,line_id,context) - if result: - return result - return res - - -class AccountStatementCompletionRule(Model): - """ - This will represent all the completion method that we can have to - fullfill the bank statement lines. You'll be able to extend them in you own module - and choose those to apply for every statement profile. - The goal of a rule is to fullfill at least the partner of the line, but - if possible also the reference because we'll use it in the reconciliation - process. The reference should contain the invoice number or the SO number - or any reference that will be matched by the invoice accounting move. - """ - - _name = "account.statement.completion.rule" - _order = "sequence asc" - - def _get_functions(self, cr, uid, context=None): - """ - List of available methods for rules. Override this to add you own. - """ - return [ - ('get_from_ref_and_invoice', 'From line reference (based on invoice number)'), - ('get_from_ref_and_so', 'From line reference (based on SO number)'), - ('get_from_label_and_partner_field', 'From line label (based on partner field)'), - ('get_from_label_and_partner_name', 'From line label (based on partner name)'), - ] - - _columns={ - 'sequence': fields.integer('Sequence', help="Lower means paresed first."), - 'name': fields.char('Name', size=128), - 'profile_ids': fields.many2many('account.statement.profil', - rel='as_rul_st_prof_rel', - string='Related statement profiles'), - 'function_to_call': fields.selection(_get_functions, 'Method'), - } - - def get_from_ref_and_invoice(self, cursor, uid, line_id, context=None): - """ - Match the partner based on the invoice number and the reference of the statement - line. Then, call the generic get_values_for_line method to complete other values. - If more than one partner matched, raise the ErrorTooManyPartner error. - - :param int/long line_id: id 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, - - ...} - """ - st_obj = self.pool.get('account.bank.statement.line') - st_line = st_obj.browse(cursor,uid,line_id) - res = {} - if st_line: - inv_obj = self.pool.get('account.invoice') - inv_id = inv_obj.search(cursor, uid, [('number', '=', st_line.ref)]) - if inv_id: - if inv_id and len(inv_id) == 1: - inv = inv_obj.browse(cursor, uid, inv_id[0]) - res['partner_id'] = inv.partner_id.id - elif inv_id and len(inv_id) > 1: - raise ErrorTooManyPartner(_('Line named "%s" was matched by more than one partner.')%(st_line.name,st_line.id)) - st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, - partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) - res.update(st_vals) - return res - - def get_from_ref_and_so(self, cursor, uid, line_id, context=None): - """ - Match the partner based on the SO number and the reference of the statement - line. Then, call the generic get_values_for_line method to complete other values. - If more than one partner matched, raise the ErrorTooManyPartner error. - - :param int/long line_id: id 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, - - ...} - """ - st_obj = self.pool.get('account.bank.statement.line') - st_line = st_obj.browse(cursor,uid,line_id) - res = {} - if st_line: - so_obj = self.pool.get('sale.order') - so_id = so_obj.search(cursor, uid, [('name', '=', st_line.ref)]) - if so_id: - if so_id and len(so_id) == 1: - so = so_obj.browse(cursor, uid, so_id[0]) - res['partner_id'] = so.partner_id.id - elif so_id and len(so_id) > 1: - raise ErrorTooManyPartner(_('Line named "%s" was matched by more than one partner.')%(st_line.name,st_line.id)) - st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, - partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) - res.update(st_vals) - return res - - - def get_from_label_and_partner_field(self, cursor, uid, line_id, context=None): - """ - Match the partner based on the label field of the statement line - and the text defined in the 'bank_statement_label' field of the partner. - Remember that we can have values separated with ; Then, call the generic - get_values_for_line method to complete other values. - If more than one partner matched, raise the ErrorTooManyPartner error. - - :param int/long line_id: id 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, - - ...} - """ - partner_obj = self.pool.get('res.partner') - st_obj = self.pool.get('account.bank.statement.line') - st_line = st_obj.browse(cursor,uid,line_id) - res = {} - compt = 0 - if st_line: - ids = partner_obj.search(cursor, uid, [['bank_statement_label', '!=', False]], context=context) - for partner in self.browse(cursor, uid, ids, context=context): - for partner_label in partner.bank_statement_label.split(';'): - if partner_label in st_line.label: - compt += 1 - res['partner_id'] = partner.id - if compt > 1: - raise ErrorTooManyPartner(_('Line named "%s" was matched by more than one partner.')%(st_line.name,st_line.id)) - if res: - st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, - partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) - res.update(st_vals) - return res - - def get_from_label_and_partner_name(self, cursor, uid, line_id, context=None): - """ - Match the partner based on the label field of the statement line - and the name of the partner. - Then, call the generic get_values_for_line method to complete other values. - If more than one partner matched, raise the ErrorTooManyPartner error. - - :param int/long line_id: id 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, - - ...} - """ - # This Method has not been tested yet ! - res = {} - st_obj = self.pool.get('account.bank.statement.line') - st_line = st_obj.browse(cursor,uid,line_id) - if st_line: - sql = "SELECT id FROM res_partner WHERE name ~* '.*%s.*'" - cursor.execute(sql, (st_line.label,)) - result = cursor.fetchall() - if len(result) > 1: - raise ErrorTooManyPartner(_('Line named "%s" was matched by more than one partner.')%(st_line.name,st_line.id)) - for id in result: - res['partner_id'] = id - if res: - st_vals = st_obj.get_values_for_line(cursor, uid, profile_id = st_line.statement_id.profile_id.id, - partner_id = res.get('partner_id',False), line_type = st_line.type, amount = st_line.amount, context = context) - res.update(st_vals) - return res - - -class AccountStatementLine(Model): - """ - Add sparse field on the statement line to allow to store all the - bank infos that are given by a bank/office. You can then add you own in your - module. The idea here is to store all bank/office infos in the additionnal_bank_fields - serialized field when importing the file. If many values, add a tab in the bank - statement line to store your specific one. Have a look in account_statement_base_import - module to see how we've done it. - """ - _inherit = "account.bank.statement.line" - - _columns={ - 'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', - help="Used by completion and import system. Adds every field that is present in your bank/office \ - statement file"), - 'label': fields.sparse(type='char', string='Label', - serialization_field='additionnal_bank_fields', - help="Generiy field to store a label given from the bank/office on which we can \ - base the default/standard providen rule."), - 'already_completed': fields.boolean("Auto-Completed", - help="When this checkbox is ticked, the auto-completion process/button will ignore this line."), - } - _defaults = { - 'already_completed': False, - } - - - def get_line_values_from_rules(self, cr, uid, ids, context=None): - """ - We'll try to find out the values related to the line based on rules setted on - the profile.. We will ignore line for which already_completed is ticked. - - :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, - - ...} - """ - profile_obj = self.pool.get('account.statement.profil') - st_obj = self.pool.get('account.bank.statement.line') - res={} - errors_stack = [] - for line in self.browse(cr,uid, ids, context): - if not line.already_completed: - try: - # Take the default values - res[line.id] = st_obj.get_values_for_line(cr, uid, profile_id = line.statement_id.profile_id.id, - line_type = line.type, amount = line.amount, context = context) - # Ask the rule - vals = profile_obj.find_values_from_rules(cr, uid, line.statement_id.profile_id.id, line.id, context) - # Merge the result - res[line.id].update(vals) - except ErrorTooManyPartner, exc: - msg = "Line ID %s had following error: %s" % (line.id, str(exc)) - errors_stack.append(msg) - if errors_stack: - msg = u"\n".join(errors_stack) - raise ErrorTooManyPartner(msg) - return res - -class AccountBankSatement(Model): - """ - We add a basic button and stuff to support the auto-completion - of the bank statement once line have been imported or manually fullfill. - """ - _inherit = "account.bank.statement" - - def button_auto_completion(self, cr, uid, ids, context=None): - """ - Complete line with values given by rules and tic the already_completed - checkbox so we won't compute them again unless the user untick them ! - """ - # TODO: Test the errors system, we should be able to complete all line that - # passed, and raise an error for all other at once.. - if not context: - context={} - stat_line_obj = self.pool.get('account.bank.statement.line') - errors_msg=False - for stat in self.browse(cr, uid, ids, context=context): - ctx = context.copy() - line_ids = map(lambda x:x.id, stat.line_ids) - try: - res = stat_line_obj.get_line_values_from_rules(cr, uid, line_ids, context=ctx) - except ErrorTooManyPartner, exc: - errors_msg = str(exc) - for id in line_ids: - vals = res.get(id, False) - if vals: - vals['already_completed'] = True - stat_line_obj.write(cr, uid, id, vals, context=ctx) - # cr.commit() - # TOTEST: I don't know if this is working... - if errors_msg: - # raise osv.except_osv(_('Error'), errors_msg) - warning = { - 'title': _('Error!'), - 'message' : errors_msg, - } - return {'warning': warning} - return True diff --git a/account_statement_base_completion/statement_view.xml b/account_statement_base_completion/statement_view.xml deleted file mode 100644 index 4c1fb2b3..00000000 --- a/account_statement_base_completion/statement_view.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - account_bank_statement_import_base.bank_statement.view_form - account.bank.statement - - - form - - - - - - - - - - - - - 10 - - - -