diff --git a/account_advanced_reconcile_transaction_ref/__openerp__.py b/account_advanced_reconcile_transaction_ref/__openerp__.py index 7ac87b57..d2b0d1cc 100644 --- a/account_advanced_reconcile_transaction_ref/__openerp__.py +++ b/account_advanced_reconcile_transaction_ref/__openerp__.py @@ -25,7 +25,7 @@ Advanced reconciliation method for the module account_advanced_reconcile Reconcile rules with transaction_ref """, - 'version': '1.0', + 'version': '1.0.1', 'author': 'Camptocamp', 'category': 'Finance', 'website': 'http://www.camptocamp.com', diff --git a/account_statement_base_completion/__init__.py b/account_statement_base_completion/__init__.py index 6c9ef1bc..a219be6a 100644 --- a/account_statement_base_completion/__init__.py +++ b/account_statement_base_completion/__init__.py @@ -19,5 +19,5 @@ # ############################################################################## -import statement -import partner +from . import partner +from . import statement diff --git a/account_statement_base_completion/__openerp__.py b/account_statement_base_completion/__openerp__.py index f6a9e806..ece29e6f 100644 --- a/account_statement_base_completion/__openerp__.py +++ b/account_statement_base_completion/__openerp__.py @@ -20,7 +20,7 @@ ############################################################################## {'name': "Bank statement base completion", - 'version': '1.0', + 'version': '1.0.1', 'author': 'Camptocamp', 'maintainer': 'Camptocamp', 'category': 'Finance', diff --git a/account_statement_base_completion/statement.py b/account_statement_base_completion/statement.py index aacb7068..61e3dbde 100644 --- a/account_statement_base_completion/statement.py +++ b/account_statement_base_completion/statement.py @@ -23,6 +23,7 @@ import traceback import sys import logging import simplejson +import inspect import psycopg2 @@ -73,14 +74,13 @@ class AccountStatementProfil(orm.Model): rel='as_rul_st_prof_rel'), } - def _get_callable(self, cr, uid, profile, context=None): + def _get_rules(self, cr, uid, profile, context=None): if isinstance(profile, (int, long)): prof = self.browse(cr, uid, profile, context=context) else: prof = profile # We need to respect the sequence order - sorted_array = sorted(prof.rule_ids, key=attrgetter('sequence')) - return tuple((x.function_to_call for x in sorted_array)) + return sorted(prof.rule_ids, key=attrgetter('sequence')) def _find_values_from_rules(self, cr, uid, calls, line, context=None): """ @@ -99,12 +99,15 @@ class AccountStatementProfil(orm.Model): if context is None: context = {} if not calls: - calls = self._get_callable(cr, uid, line['profile_id'], context=context) + calls = self._get_rules(cr, uid, line['profile_id'], context=context) rule_obj = self.pool.get('account.statement.completion.rule') for call in calls: - method_to_call = getattr(rule_obj, call) - result = method_to_call(cr, uid, line, context) + method_to_call = getattr(rule_obj, call.function_to_call) + if len(inspect.getargspec(method_to_call).args) == 6: + result = method_to_call(cr, uid, call.id, line, context) + else: + result = method_to_call(cr, uid, line, context) if result: result['already_completed'] = True return result @@ -181,7 +184,7 @@ class AccountStatementCompletionRule(orm.Model): inv = self._find_invoice(cr, uid, line, inv_type, context=context) if inv: # FIXME use only commercial_partner_id of invoice in 7.1 - # this is for backward compatibility in 7.0 before + # this is for backward compatibility in 7.0 before # the refactoring of res.partner if hasattr(inv, 'commercial_partner_id'): partner_id = inv.commercial_partner_id.id @@ -316,9 +319,12 @@ class AccountStatementCompletionRule(orm.Model): if not context['partner_memoizer']: return res st_obj = self.pool.get('account.bank.statement.line') - sql = "SELECT id FROM res_partner WHERE name ~* %s and id in %s" - pattern = ".*%s.*" % re.escape(st_line['name']) - cr.execute(sql, (pattern, context['partner_memoizer'])) + # regexp_replace(name,'([^a-zA-Z0-9 -])', '\\\1', 'g'), 'i') escape the column name to avoid false positive. (ex 'jho..doe' -> 'joh\.\.doe' + sql = """SELECT id FROM ( + SELECT id, regexp_matches(%s, regexp_replace(name,'([^[:alpha:]0-9 -])', %s, 'g'), 'i') AS name_match FROM res_partner + WHERE id IN %s) AS res_patner_matcher + WHERE name_match IS NOT NULL""" + cr.execute(sql, (st_line['name'], r"\\\1", context['partner_memoizer'])) result = cr.fetchall() if not result: return res @@ -329,7 +335,7 @@ class AccountStatementCompletionRule(orm.Model): res['partner_id'] = result[0][0] st_vals = st_obj.get_values_for_line(cr, uid, - profile_id=st_line['porfile_id'], + profile_id=st_line['profile_id'], master_account_id=st_line['master_account_id'], partner_id=res['partner_id'], line_type=False, @@ -415,7 +421,7 @@ class AccountStatementLine(orm.Model): """ 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']) + 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() @@ -426,10 +432,9 @@ class AccountStatementLine(orm.Model): serialized = st_copy.setdefault(col.serialization_field, {}) serialized[k] = st_copy[k] for k in to_json_k: - st_copy[k] = simplejson.dumps(st_copy[k]) + st_copy[k] = simplejson.dumps(st_copy[k]) values.append(st_copy) return values - def _insert_lines(self, cr, uid, statement_store, context=None): """ Do raw insert into database because ORM is awfully slow @@ -453,7 +458,7 @@ class AccountStatementLine(orm.Model): when cheking security. TODO / WARM: sparse fields are skipped by the method. IOW, if your completion rule update an sparse field, the updated value will never - be stored in the database. It would be safer to call the update method + be stored in the database. It would be safer to call the update method from the ORM for records updating this kind of fields. """ cols = self._get_available_columns([vals]) @@ -467,7 +472,7 @@ class AccountStatementLine(orm.Model): sql_err.pgerror) -class AccountBankSatement(orm.Model): +class AccountBankStatement(orm.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. @@ -526,7 +531,7 @@ class AccountBankSatement(orm.Model): ctx = context.copy() ctx['line_ids'] = tuple((x.id for x in stat.line_ids)) b_profile = stat.profile_id - rules = profile_obj._get_callable(cr, uid, b_profile, context=context) + rules = profile_obj._get_rules(cr, uid, b_profile, context=context) profile_id = b_profile.id # Only for perfo even it gains almost nothing master_account_id = b_profile.receivable_account_id master_account_id = master_account_id.id if master_account_id else False diff --git a/account_statement_base_completion/tests/__init__.py b/account_statement_base_completion/tests/__init__.py new file mode 100644 index 00000000..6f9e09ea --- /dev/null +++ b/account_statement_base_completion/tests/__init__.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# +# +# Authors: Laurent Mignon +# Copyright (c) 2014 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 . +# +# + +from . import test_base_completion + +checks = [ + test_base_completion +] diff --git a/account_statement_base_completion/tests/test_base_completion.py b/account_statement_base_completion/tests/test_base_completion.py new file mode 100644 index 00000000..d9416eff --- /dev/null +++ b/account_statement_base_completion/tests/test_base_completion.py @@ -0,0 +1,95 @@ +# -*- coding: utf-8 -*- +# +# +# Authors: Laurent Mignon +# Copyright (c) 2014 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 . +# +# +from openerp.tests import common +import time +from collections import namedtuple + +name_completion_case = namedtuple("name_completion_case", ["partner_name", "line_label", "should_match"]) +NAMES_COMPLETION_CASES = [ + name_completion_case("Acsone", "Line for Acsone SA", True), + name_completion_case("Acsone", "Line for Acsone", True), + name_completion_case("Acsone", "Acsone for line", True), + name_completion_case("acsone", "Acsone for line", True), + name_completion_case("Acsone SA", "Line for Acsone SA test", True), + name_completion_case("Ac..ne", "Acsone for line", False), + name_completion_case("é@|r{}", "Acsone é@|r{} for line", True), + name_completion_case("Acsone", "A..one for line", False), + name_completion_case("A.one SA", "A.one SA for line", True), + name_completion_case("Acsone SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", False), + name_completion_case("Acsone ([^a-zA-Z0-9 -]) SA", "Line for Acsone ([^a-zA-Z0-9 -]) SA test", True), + ] + + +class base_completion(common.TransactionCase): + + def setUp(self): + super(base_completion, self).setUp() + self.company_a = self.browse_ref('base.main_company') + self.profile_obj = self.registry("account.statement.profile") + self.partner_obj = self.registry("res.partner") + self.account_bank_statement_obj = self.registry("account.bank.statement") + self.account_bank_statement_line_obj = self.registry("account.bank.statement.line") + self.journal_id = self.ref("account.bank_journal") + self.partner_id = self.ref('base.main_partner') + self.account_id = self.ref("account.a_recv") + self.partner_id = self.ref("base.res_partner_12") + + def test_name_completion(self): + """Test complete partner_id from statement line label + Test the automatic completion of the partner_id based if the name of the partner appears in + the statement line label + """ + self.completion_rule_id = self.ref('account_statement_base_completion.bank_statement_completion_rule_3') + # Create the profile + self.profile_id = self.profile_obj.create(self.cr, self.uid, { + "name": "TEST", + "commission_account_id": self.account_id, + "journal_id": self.journal_id, + "rule_ids": [(6, 0, [self.completion_rule_id])]}) + # 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 + }) + + for case in NAMES_COMPLETION_CASES: + self.partner_obj.write(self.cr, self.uid, self.partner_id, {'name': case.partner_name}) + statement_line_id = self.account_bank_statement_line_obj.create(self.cr, self.uid, { + 'amount': 1000.0, + 'name': case.line_label, + 'ref': 'My ref', + 'statement_id': self.statement_id, + }) + statement_line = self.account_bank_statement_line_obj.browse(self.cr, self.uid, statement_line_id) + 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, statement_line_id) + if case.should_match: + self.assertEquals(self.partner_id, statement_line.partner_id['id'], + "Missing expected partner id after completion (partner_name: %s, line_name: %s)" % (case.partner_name, case.line_label)) + else: + self.assertNotEquals(self.partner_id, statement_line.partner_id['id'], + "Partner id should be empty after completion(partner_name: %s, line_name: %s)" % (case.partner_name, case.line_label)) diff --git a/account_statement_base_import/__openerp__.py b/account_statement_base_import/__openerp__.py index 086af048..3ff7d74f 100644 --- a/account_statement_base_import/__openerp__.py +++ b/account_statement_base_import/__openerp__.py @@ -20,7 +20,7 @@ ############################################################################## {'name': "Bank statement base import", - 'version': '1.0', + 'version': '1.0.3', 'author': 'Camptocamp', 'maintainer': 'Camptocamp', 'category': 'Finance', diff --git a/account_statement_base_import/parser/parser.py b/account_statement_base_import/parser/parser.py index cce55eea..b17aded1 100644 --- a/account_statement_base_import/parser/parser.py +++ b/account_statement_base_import/parser/parser.py @@ -26,7 +26,7 @@ from datetime import datetime def UnicodeDictReader(utf8_data, **kwargs): sniffer = csv.Sniffer() pos = utf8_data.tell() - sample_data = utf8_data.read(1024) + sample_data = utf8_data.read(2048) utf8_data.seek(pos) dialect = sniffer.sniff(sample_data, delimiters=',;\t') csv_reader = csv.DictReader(utf8_data, dialect=dialect, **kwargs) @@ -115,6 +115,19 @@ class BankStatementImportParser(object): """ return NotImplementedError + def get_st_vals(self): + """ + This method return a dict of vals that ca be passed to + create method of statement. + :return: dict of vals that represent additional infos for the statement + """ + return { + 'name': self.statement_name or '/', + 'balance_start': self.balance_start, + 'balance_end_real': self.balance_end, + 'date': self.statement_date or datetime.now() + } + def get_st_line_vals(self, line, *args, **kwargs): """ Implement a method in your parser that must return a dict of vals that can be @@ -155,37 +168,6 @@ class BankStatementImportParser(object): self._post(*args, **kwargs) return self.result_row_list - def get_start_balance(self, *args, **kwargs): - """ - This is called by the importation method to set the balance start - amount in the bank statement. - return: float of the balance start (self.balance_start) - """ - return self.balance_start - - def get_end_balance(self, *args, **kwargs): - """ - This is called by the importation method to set the balance end - amount in the bank statement. - return: float of the balance end (self.balance_end) - """ - return self.balance_end - - def get_statement_name(self, *args, **kwargs): - """ - This is called by the importation method to set the statement - name in the bank statement. - return: string of the statement name (self.statement_name) - """ - return self.statement_name or '/' - - def get_statement_date(self, *args, **kwargs): - """ - This is called by the importation method to set the statement - date in the bank statement. - return: datetime of the statement date (self.statement_date) - """ - return self.statement_date or datetime.now() def itersubclasses(cls, _seen=None): """ diff --git a/account_statement_base_import/statement.py b/account_statement_base_import/statement.py index 960616d1..c88727b5 100644 --- a/account_statement_base_import/statement.py +++ b/account_statement_base_import/statement.py @@ -32,11 +32,12 @@ class AccountStatementProfil(Model): _inherit = "account.statement.profile" def get_import_type_selection(self, cr, uid, context=None): - """ - Has to be inherited to add parser - """ + """This is the method to be inherited for adding the parser""" return [('generic_csvxls_so', 'Generic .csv/.xls based on SO Name')] + def _get_import_type_selection(self, cr, uid, context=None): + return self.get_import_type_selection(cr, uid, context=context) + _columns = { 'launch_import_completion': fields.boolean( "Launch completion after import", @@ -46,14 +47,17 @@ class AccountStatementProfil(Model): # we remove deprecated as it floods logs in standard/warning level sob... 'rec_log': fields.text('log', readonly=True), # Deprecated 'import_type': fields.selection( - get_import_type_selection, + _get_import_type_selection, 'Type of import', required=True, help="Choose here the method by which you want to import bank" "statement for this profile."), - } + _defaults = { + 'import_type': 'generic_csvxls_so' + } + def _write_extra_statement_lines( self, cr, uid, parser, result_row_list, profile, statement_id, context): """Insert extra lines after the main statement lines. @@ -85,12 +89,16 @@ class AccountStatementProfil(Model): context=context) return True - def prepare_statetement_lines_vals( + #Deprecated remove on V8 + def prepare_statetement_lines_vals(self, *args, **kwargs): + return self.prepare_statement_lines_vals(*args, **kwargs) + + def prepare_statement_lines_vals( self, cr, uid, parser_vals, account_payable, account_receivable, statement_id, context): """ Hook to build the values of a line from the parser returned values. At - least it fullfill the statement_id and account_id. Overide it to add your + least it fullfill the statement_id and account_id. Override it to add your own completion if needed. :param dict of vals from parser for account.bank.statement.line (called by @@ -126,14 +134,14 @@ class AccountStatementProfil(Model): values['type'] = 'general' return values - - def _prepare_statement_vals(self, cr, uid, prof, parser, context=None): - return { - 'profile_id': prof.id, - 'name': parser.get_statement_name(), - 'balance_start': parser.get_start_balance(), - 'balance_end_real': parser.get_end_balance(), - } + def prepare_statement_vals(self, cr, uid, profile_id, result_row_list, parser, context): + """ + Hook to build the values of the statement from the parser and + the profile. + """ + vals = {'profile_id': profile_id} + vals.update(parser.get_st_vals()) + return vals def statement_import(self, cr, uid, ids, profile_id, file_stream, ftype="csv", context=None): """ @@ -168,8 +176,11 @@ class AccountStatementProfil(Model): _("Column %s you try to import is not " "present in the bank statement line!") % col) - st_vals = self._prepare_statement_vals(cr, uid, prof, parser, context=context) - statement_id = statement_obj.create(cr, uid, st_vals, context=context) + statement_vals = self.prepare_statement_vals(cr, uid, prof.id, result_row_list, parser, context) + statement_id = statement_obj.create(cr, uid, + statement_vals, + context=context) + if prof.receivable_account_id: account_receivable = account_payable = prof.receivable_account_id.id else: @@ -180,7 +191,7 @@ class AccountStatementProfil(Model): statement_store = [] for line in result_row_list: parser_vals = parser.get_st_line_vals(line) - values = self.prepare_statetement_lines_vals( + values = self.prepare_statement_lines_vals( cr, uid, parser_vals, account_payable, account_receivable, statement_id, context) statement_store.append(values) @@ -215,7 +226,6 @@ class AccountStatementProfil(Model): context) except Exception: - statement_obj.unlink(cr, uid, [statement_id], context=context) error_type, error_value, trbk = sys.exc_info() st = "Error: %s\nDescription: %s\nTraceback:" % (error_type.__name__, error_value) st += ''.join(traceback.format_tb(trbk, 30)) diff --git a/account_statement_commission/commission.py b/account_statement_commission/commission.py index f4d0fc74..b98227b8 100644 --- a/account_statement_commission/commission.py +++ b/account_statement_commission/commission.py @@ -2,9 +2,11 @@ from openerp.tools.translate import _ import datetime from openerp.osv import orm, fields + def float_or_zero(val): return float(val) if val else 0.0 + class AccountStatementProfil(orm.Model): _inherit = "account.statement.profile" @@ -22,7 +24,7 @@ class AccountStatementProfil(orm.Model): commission_analytic_id = profile.commission_analytic_id and profile.commission_analytic_id.id or False comm_values = { 'name': 'IN ' + _('Commission line'), - 'date': parser.get_statement_date(), + 'date': parser.get_st_vals().get('date') or datetime.datetime.now(), 'amount': global_commission_amount, 'partner_id': partner_id, 'type': 'general', @@ -36,6 +38,7 @@ class AccountStatementProfil(orm.Model): statement_line_obj = self.pool.get('account.bank.statement.line') statement_line_obj.create(cr, uid, comm_values, context=context) + class AccountStatementLineWithCommission(orm.Model): _inherit = "account.bank.statement.line" _columns = { @@ -45,6 +48,7 @@ class AccountStatementLineWithCommission(orm.Model): serialization_field='additionnal_bank_fields'), } + class CreditPartnerStatementImporter(orm.TransientModel): _inherit = "credit.statement.import" diff --git a/account_statement_ext/__openerp__.py b/account_statement_ext/__openerp__.py index c6000063..213d51c6 100644 --- a/account_statement_ext/__openerp__.py +++ b/account_statement_ext/__openerp__.py @@ -20,7 +20,7 @@ ############################################################################## {'name': "Bank statement extension and profiles", - 'version': '1.3.0', + 'version': '1.3.2', 'author': 'Camptocamp', 'maintainer': 'Camptocamp', 'category': 'Finance', diff --git a/account_statement_ext/statement.py b/account_statement_ext/statement.py index 2ca8627b..bab025cd 100644 --- a/account_statement_ext/statement.py +++ b/account_statement_ext/statement.py @@ -118,7 +118,7 @@ class AccountStatementProfile(Model): -class AccountBankSatement(Model): +class AccountBankStatement(Model): """ We improve the bank statement class mostly for : - Removing the period and compute it from the date of each line. @@ -207,14 +207,17 @@ class AccountBankSatement(Model): profile_obj = self.pool.get('account.statement.profile') profile = profile_obj.browse(cr, uid, vals['profile_id'], context=context) vals['journal_id'] = profile.journal_id.id - return super(AccountBankSatement, self).create(cr, uid, vals, context=context) + return super(AccountBankStatement, self + ).create(cr, uid, vals, context=context) def _get_period(self, cr, uid, date, context=None): - """ - Find matching period for date, used in the statement line creation. - """ + """Return matching period for a date.""" + if context is None: + context = {} period_obj = self.pool.get('account.period') - periods = period_obj.find(cr, uid, dt=date, context=context) + local_context = context.copy() + local_context['account_period_prefer_normal'] = True + periods = period_obj.find(cr, uid, dt=date, context=local_context) return periods and periods[0] or False def _check_company_id(self, cr, uid, ids, context=None): @@ -253,8 +256,9 @@ class AccountBankSatement(Model): """ if context is None: context = {} - res = super(AccountBankSatement, self)._prepare_move( - cr, uid, st_line, st_line_number, context=context) + res = super(AccountBankStatement, self + )._prepare_move(cr, uid, st_line, st_line_number, + context=context) ctx = context.copy() ctx['company_id'] = st_line.company_id.id period_id = self._get_period(cr, uid, st_line.date, context=ctx) @@ -283,7 +287,7 @@ class AccountBankSatement(Model): """ if context is None: context = {} - res = super(AccountBankSatement, self)._prepare_move_line_vals( + res = super(AccountBankStatement, self)._prepare_move_line_vals( cr, uid, st_line, move_id, debit, credit, currency_id=currency_id, amount_currency=amount_currency, @@ -307,10 +311,9 @@ class AccountBankSatement(Model): create the move from. :return: int/long of the res.partner to use as counterpart """ - bank_partner_id = super(AccountBankSatement, self)._get_counter_part_partner(cr, - uid, - st_line, - context=context) + bank_partner_id = super(AccountBankStatement, self + )._get_counter_part_partner(cr, uid, st_line, + context=context) # get the right partner according to the chosen profile if st_line.statement_id.profile_id.force_partner_on_bank: bank_partner_id = st_line.statement_id.profile_id.partner_id.id @@ -540,8 +543,9 @@ class AccountBankSatement(Model): """ st = self.browse(cr, uid, st_id, context=context) if st.balance_check: - return super(AccountBankSatement, self).balance_check( - cr, uid, st_id, journal_type, context=context) + return super(AccountBankStatement, self + ).balance_check(cr, uid, st_id, journal_type, + context=context) else: return True @@ -561,7 +565,7 @@ class AccountBankSatement(Model): 'balance_check': import_config.balance_check}} -class AccountBankSatementLine(Model): +class AccountBankStatementLine(Model): """ Override to compute the period from the date of the line, add a method to retrieve the values for a line from the profile. Override the on_change method to take care of @@ -571,14 +575,15 @@ class AccountBankSatementLine(Model): _inherit = "account.bank.statement.line" def _get_period(self, cr, uid, context=None): - """ - Return a period from a given date in the context. - """ + """Return matching period for a date.""" if context is None: context = {} + period_obj = self.pool['account.period'] date = context.get('date') + local_context = context.copy() + local_context['account_period_prefer_normal'] = True try: - periods = self.pool.get('account.period').find(cr, uid, dt=date) + periods = period_obj.find(cr, uid, dt=date, context=local_context) except osv.except_osv: # if no period defined, we are certainly at installation time return False @@ -656,6 +661,9 @@ class AccountBankSatementLine(Model): if partner_id: part = obj_partner.browse(cr, uid, partner_id, context=context) part = part.commercial_partner_id + # When the method is called from bank statement completion, + # ensure that the line's partner is a commercial + # (accounting) entity res['partner_id'] = part.id pay_account = part.property_account_payable.id receiv_account = part.property_account_receivable.id @@ -692,11 +700,9 @@ class AccountBankSatementLine(Model): Keep the same features as in standard and call super. If an account is returned, call the method to compute line values. """ - res = super(AccountBankSatementLine, self).onchange_type(cr, uid, - line_id, - partner_id, - line_type, - context=context) + res = super(AccountBankStatementLine, self + ).onchange_type(cr, uid, line_id, partner_id, + line_type, context=context) if 'account_id' in res['value']: result = self.get_values_for_line(cr, uid, profile_id=profile_id, diff --git a/account_statement_no_invoice_import/__init__.py b/account_statement_no_invoice_import/__init__.py new file mode 100644 index 00000000..b42d6e1b --- /dev/null +++ b/account_statement_no_invoice_import/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# module for OpenERP +# Copyright (C) 2013-TODAY Akretion . +# @author Sébastien BEAU +# +# 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 . +# +############################################################################### + diff --git a/account_statement_no_invoice_import/__openerp__.py b/account_statement_no_invoice_import/__openerp__.py new file mode 100644 index 00000000..abc1a218 --- /dev/null +++ b/account_statement_no_invoice_import/__openerp__.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +############################################################################### +# +# module for OpenERP +# Copyright (C) 2013-TODAY Akretion . +# @author Sébastien BEAU +# +# 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': 'account bank statement no invoice import', + 'version': '0.1', + 'category': 'Generic Modules/Others', + 'license': 'AGPL-3', + 'description': """Module that remove the 'Import invoices' button on bank statement""", + 'author': 'Akretion', + 'website': 'http://www.akretion.com/', + 'depends': [ + 'account_voucher', + ], + 'data': [ + 'statement_view.xml', + ], + 'demo': [], + 'installable': True, + 'active': False, +} diff --git a/account_statement_no_invoice_import/statement_view.xml b/account_statement_no_invoice_import/statement_view.xml new file mode 100644 index 00000000..67920f41 --- /dev/null +++ b/account_statement_no_invoice_import/statement_view.xml @@ -0,0 +1,21 @@ + + + + + + + + + account_bank_statement_simple_view.account_bank_statement.view_form + account.bank.statement + + + form + + + + + + + diff --git a/account_statement_ofx_import/statement.py b/account_statement_ofx_import/statement.py index c5b06fe8..15060360 100644 --- a/account_statement_ofx_import/statement.py +++ b/account_statement_ofx_import/statement.py @@ -33,14 +33,3 @@ class AccountStatementProfil(orm.Model): context=context) selection.append(('ofx_so', _('OFX - Open Financial Exchange'))) return selection - - _columns = { - 'import_type': fields.selection( - get_import_type_selection, - 'Type of import', - required=True, - help="Choose here the method by which you want to import bank" - "statement for this profile."), - - } - diff --git a/account_statement_regex_account_completion/__init__.py b/account_statement_regex_account_completion/__init__.py new file mode 100644 index 00000000..41101e40 --- /dev/null +++ b/account_statement_regex_account_completion/__init__.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Authors: Laetitia Gangloff +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) +# All Rights Reserved +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs. +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contact a Free Software +# Service Company. +# +# 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 . import statement + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_statement_regex_account_completion/__openerp__.py b/account_statement_regex_account_completion/__openerp__.py new file mode 100644 index 00000000..9acb1940 --- /dev/null +++ b/account_statement_regex_account_completion/__openerp__.py @@ -0,0 +1,56 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Authors: Laetitia Gangloff +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) +# All Rights Reserved +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs. +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contact a Free Software +# Service Company. +# +# 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": "Account Statement Regex Account Completion addon", + "version": "0.1", + "author": "ACSONE SA/NV", + "category": "Other", + "website": "http://www.acsone.eu", + "depends": ["account_statement_base_completion", + ], + "description": """ + +Account Statement Regex Account Completion addon +========================= + +- Add a completion method based on a specified regular expression + and update account to use in the bank statement line with the specified account. +""", + "data": ['statement_view.xml', + ], + "demo": [], + "test": [], + "active": False, + "license": "AGPL-3", + "installable": True, + "auto_install": False, + "application": False, +} +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_statement_regex_account_completion/i18n/account_statement_regex_account_completion.pot b/account_statement_regex_account_completion/i18n/account_statement_regex_account_completion.pot new file mode 100644 index 00000000..42587093 --- /dev/null +++ b/account_statement_regex_account_completion/i18n/account_statement_regex_account_completion.pot @@ -0,0 +1,32 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_statement_regex_account_completion +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-01-22 10:59+0000\n" +"PO-Revision-Date: 2014-01-22 10:59+0000\n" +"Last-Translator: <>\n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: \n" +"Plural-Forms: \n" + +#. module: account_statement_regex_account_completion +#: field:account.statement.completion.rule,regex:0 +msgid "Regular Expression" +msgstr "" + +#. module: account_statement_regex_account_completion +#: field:account.statement.completion.rule,account_id:0 +msgid "Account to set" +msgstr "" + +#. module: account_statement_regex_account_completion +#: model:ir.model,name:account_statement_regex_account_completion.model_account_statement_completion_rule +msgid "account.statement.completion.rule" +msgstr "" + diff --git a/account_statement_regex_account_completion/i18n/fr.po b/account_statement_regex_account_completion/i18n/fr.po new file mode 100644 index 00000000..b2bdf2a0 --- /dev/null +++ b/account_statement_regex_account_completion/i18n/fr.po @@ -0,0 +1,32 @@ +# Translation of OpenERP Server. +# This file contains the translation of the following modules: +# * account_statement_regex_account_completion +# +msgid "" +msgstr "" +"Project-Id-Version: OpenERP Server 7.0\n" +"Report-Msgid-Bugs-To: \n" +"POT-Creation-Date: 2014-01-22 10:59+0000\n" +"PO-Revision-Date: 2014-01-23 17:42+0000\n" +"Last-Translator: Laetitia Gangloff (Acsone) \n" +"Language-Team: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=UTF-8\n" +"Content-Transfer-Encoding: 8bit\n" +"X-Launchpad-Export-Date: 2014-03-01 05:55+0000\n" +"X-Generator: Launchpad (build 16948)\n" + +#. module: account_statement_regex_account_completion +#: field:account.statement.completion.rule,regex:0 +msgid "Regular Expression" +msgstr "Expression Régulière" + +#. module: account_statement_regex_account_completion +#: field:account.statement.completion.rule,account_id:0 +msgid "Account to set" +msgstr "Compte à utiliser" + +#. module: account_statement_regex_account_completion +#: model:ir.model,name:account_statement_regex_account_completion.model_account_statement_completion_rule +msgid "account.statement.completion.rule" +msgstr "account.statement.completion.rule" diff --git a/account_statement_regex_account_completion/statement.py b/account_statement_regex_account_completion/statement.py new file mode 100644 index 00000000..e54f136e --- /dev/null +++ b/account_statement_regex_account_completion/statement.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Authors: Laetitia Gangloff +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) +# All Rights Reserved +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs. +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contact a Free Software +# Service Company. +# +# 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 +from openerp.osv import fields + +import re + + +class AccountStatementCompletionRule(Model): + """Add a rule to complete account based on a regular expression""" + + _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(('set_account', + 'Set account for line labels matching a regular expression')) + return res + + _columns = { + 'function_to_call': fields.selection(_get_functions, 'Method'), + 'regex': fields.char('Regular Expression', size=128), + 'account_id': fields.many2one('account.account', string="Account to set"), + } + + def set_account(self, cr, uid, id, st_line, context=None): + """ + If line name match regex, update account_id + 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, + ...} + """ + name = st_line['name'] + res = {} + if name: + rule = self.browse(cr, uid, id, context=context) + if re.match(rule.regex, name): + res['account_id'] = rule.account_id.id + return res + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_statement_regex_account_completion/statement_view.xml b/account_statement_regex_account_completion/statement_view.xml new file mode 100644 index 00000000..2dd4e204 --- /dev/null +++ b/account_statement_regex_account_completion/statement_view.xml @@ -0,0 +1,21 @@ + + + + + + account.statement.completion.rule.view (account_statement_regex_account_completion) + account.statement.completion.rule + + form + + + + + + + + + + + + diff --git a/account_statement_regex_account_completion/tests/__init__.py b/account_statement_regex_account_completion/tests/__init__.py new file mode 100644 index 00000000..826f535a --- /dev/null +++ b/account_statement_regex_account_completion/tests/__init__.py @@ -0,0 +1,36 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Authors: Laetitia Gangloff +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) +# All Rights Reserved +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs. +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contact a Free Software +# Service Company. +# +# 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 . import test_regex_account_completion + +checks = [ + test_regex_account_completion +] + +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4: diff --git a/account_statement_regex_account_completion/tests/test_regex_account_completion.py b/account_statement_regex_account_completion/tests/test_regex_account_completion.py new file mode 100644 index 00000000..64958844 --- /dev/null +++ b/account_statement_regex_account_completion/tests/test_regex_account_completion.py @@ -0,0 +1,91 @@ +# -*- coding: utf-8 -*- +############################################################################## +# +# Authors: Laetitia Gangloff +# Copyright (c) 2014 Acsone SA/NV (http://www.acsone.eu) +# All Rights Reserved +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs. +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly advised to contact a Free Software +# Service Company. +# +# 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.tests import common +import time + +ACC_NUMBER = "BE38733040385372" + + +class test_regex_account_completion(common.TransactionCase): + + def prepare(self): + self.account_bank_statement_obj = self.registry("account.bank.statement") + self.account_bank_statement_line_obj = self.registry("account.bank.statement.line") + self.account_id = self.ref('account.a_expense') + # create the completion rule + rule_vals = {'function_to_call': 'set_account', + 'regex': '^My statement', + 'account_id': self.account_id} + completion_rule_id = self.registry("account.statement.completion.rule").create(self.cr, self.uid, rule_vals) + + # Create the profile + journal_id = self.ref("account.bank_journal") + profile_id = self.registry("account.statement.profile").create(self.cr, self.uid, { + "name": "TEST", + "commission_account_id": self.ref("account.a_recv"), + "journal_id": journal_id, + "rule_ids": [(6, 0, [completion_rule_id])]}) + + # 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": journal_id, + "profile_id": profile_id + }) + + # Create two bank statement lines + self.statement_line1_id = self.account_bank_statement_line_obj.create(self.cr, self.uid, { + 'amount': 1000.0, + 'name': 'My statement', + 'ref': 'My ref', + 'statement_id': self.statement_id, + 'partner_acc_number': ACC_NUMBER + }) + + self.statement_line2_id = self.account_bank_statement_line_obj.create(self.cr, self.uid, { + 'amount': 2000.0, + 'name': 'My second statement', + 'ref': 'My second ref', + 'statement_id': self.statement_id, + 'partner_acc_number': ACC_NUMBER + }) + + def test_00(self): + """Test the automatic completion on account + """ + self.prepare() + statement_obj = self.account_bank_statement_obj.browse(self.cr, self.uid, self.statement_id) + statement_obj.button_auto_completion() + statement_line1 = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line1_id) + self.assertEquals(self.account_id, statement_line1.account_id.id, "The account should be the account of the completion") + statement_line2 = self.account_bank_statement_line_obj.browse(self.cr, self.uid, self.statement_line2_id) + self.assertNotEqual(self.account_id, statement_line2.account_id.id, "The account should be not the account of the completion") diff --git a/statement_voucher_killer/__openerp__.py b/statement_voucher_killer/__openerp__.py index 2460cd9a..1e5f2f1d 100644 --- a/statement_voucher_killer/__openerp__.py +++ b/statement_voucher_killer/__openerp__.py @@ -39,9 +39,9 @@ line will be take from imported line in this order: 'author': 'Camptocamp', 'website': 'http://www.camptocamp.com', 'depends': ['account_voucher', 'account_payment'], - 'init_xml': [], - 'update_xml': [], - 'demo_xml': [], + 'data': [ + 'statement_view.xml', + ], 'test': [], 'installable': True, 'active': False, diff --git a/statement_voucher_killer/statement_view.xml b/statement_voucher_killer/statement_view.xml new file mode 100644 index 00000000..e0ceda0a --- /dev/null +++ b/statement_voucher_killer/statement_view.xml @@ -0,0 +1,20 @@ + + + + + + + + + account.bank.statement + + + form + + + + + + + +