diff --git a/account_statement_ext/file_parser/__init__.py b/account_statement_base_completion/__init__.py similarity index 94% rename from account_statement_ext/file_parser/__init__.py rename to account_statement_base_completion/__init__.py index b0665b1c..f6c46966 100644 --- a/account_statement_ext/file_parser/__init__.py +++ b/account_statement_base_completion/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- ############################################################################## # -# Author: Nicolas Bessi +# Author: Joel Grand-Guillaume # Copyright 2011-2012 Camptocamp SA # # This program is free software: you can redistribute it and/or modify @@ -19,4 +19,4 @@ # ############################################################################## -import parser \ No newline at end of file +import statement \ No newline at end of file diff --git a/account_statement_base_completion/__openerp__.py b/account_statement_base_completion/__openerp__.py new file mode 100644 index 00000000..fb86b19e --- /dev/null +++ b/account_statement_base_completion/__openerp__.py @@ -0,0 +1,47 @@ +# -*- 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. + + It will also take care of the chosen profile to make his work. + """, + 'website': 'http://www.camptocamp.com', + 'init_xml': [], + 'update_xml': [ + 'statement_view.xml', + ], + 'demo_xml': [], + 'test': [], + 'installable': True, + 'images': [], + 'auto_install': False, + 'license': 'AGPL-3', + 'active': False, +} diff --git a/account_statement_base_completion/partner.py b/account_statement_base_completion/partner.py new file mode 100644 index 00000000..1dfcbc1e --- /dev/null +++ b/account_statement_base_completion/partner.py @@ -0,0 +1,83 @@ +# -*- encoding: utf-8 -*- +################################################################################# +# # +# Copyright (C) 2011 Akretion 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 . # +# # +################################################################################# + +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 thi method in your statement profile)."), + } + + # def get_partner_from_order_ref(self, cr, uid, order_ref, context=None): + # order_obj = self.pool.get('sale.order') + # so_id = order_obj.search(cr, uid, [('name', '=', order_ref)], context=context) + # if so_id: + # so = order_obj.browse(cr, uid, so_id, context=context)[0] + # return so.partner_id.id + # return False + # + # def get_partner_from_name(self, cr, uid, partner_name, context=None): + # #print 'try to get partner from name', partner_name + # return False + # + # def get_partner_from_email(self, cr, uid, partner_email, context=None): + # address_ids = self.pool.get('res.partner.address').search(cr, uid, [['email', '=', partner_email]], context=context) + # if address_ids: + # partner_id = self.search(cr, uid, [['address', 'in', address_ids]], context=context) + # return partner_id and partner_id[0] + # return False + + def get_partner_from_label_based_on_bank_statement_label(self, cr, uid, label, context=None): + ids = self.search(cr, uid, [['bank_statement_label', '!=', False]], context=context) + for partner in self.browse(cr, uid, ids, context=context): + for partner_label in partner.bank_statement_label.split(';'): + if partner_label in label: + return partner.id + return False + + def get_supplier_partner_from_label_based_on_name(self, cr, uid, label, context=None): + supplier_ids = self.search(cr, uid, [['supplier', '=', True]], context=context) + for partner in self.browse(cr, uid, supplier_ids, context=context): + if partner.name in label: + return partner.id + return False + + def get_partner_account(self, cr, uid, id, amount, context=None): + partner = self.browse(cr, uid, id, context=context) + if partner.supplier and not partner.customer: + return partner.property_account_payable.id + if partner.customer and not partner.supplier: + return partner.property_account_receivable.id + + if amount >0: + return partner.property_account_receivable.id + else: + return partner.property_account_payable.id + + + +res_partner() diff --git a/account_statement_base_completion/partner_view.xml b/account_statement_base_completion/partner_view.xml new file mode 100644 index 00000000..c7ec3f1a --- /dev/null +++ b/account_statement_base_completion/partner_view.xml @@ -0,0 +1,22 @@ + + + + + + + + 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 new file mode 100644 index 00000000..859840c8 --- /dev/null +++ b/account_statement_base_completion/statement.py @@ -0,0 +1,201 @@ +# -*- 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 + +class AccountStatementProfil(Model): + _inherit = "account.statement.profil" + + _columns={ + # 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'), + + 'rule_ids':fields.many2many('account.statement.completion.rule', + rel='account_statement_rule_statement_profile_to_rel', + 'profile_id','rule_id', + 'Related statement profiles'), + } + + def find_partner_by_rules(self, cr, uid, ids, field_value, context=None): + """This method will execute all rules, in their sequence order, + to match a partner for the given statement.line and return his id.""" + if not context: + context={} + partner_id = False + for profile in self.browse(cr, uid, ids, context=context): + for rule in profile.rule_ids: + method_to_call = getattr(rule, rule.function_to_call) + partner_id = method_to_call(cr,uid,field_value,context) + if partner_id: + return partner_id + return partner_id + + +class AccountStatementCompletionRule(Model): + """This will represent all the completion method that we can have to + fullfill the bank statement. You'll be able to extend them in you own module + and choose those to apply for every statement profile.""" + + _name = "account.statement.completion.rule" + _order = "sequence asc" + + _get_functions = [('get_from_label_and_partner_field', 'From line label (based on partner field)'),\ + ('in', 'External -> OpenERP'), ('out', 'External <- OpenERP')] + + _columns={ + 'sequence': fields.integer('Sequence'), + 'name': fields.char('Name') + 'profile_ids':fields.many2many('account.statement.profil', + rel='account_statement_rule_statement_profile_to_rel', + 'rule_id', 'profile_id', + 'Related statement profiles'), + 'function_to_call': fields.selection(_get_functions, 'Type'), + } + + def get_from_label_and_partner_field(self, cr, uid, field_value, 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 ;""" + partner_obj = self.pool.get('res.partner') + ids = partner_obj.search(cr, uid, [['bank_statement_label', '!=', False]], context=context) + for partner in self.browse(cr, uid, ids, context=context): + for partner_label in partner.bank_statement_label.split(';'): + if partner_label in field_value: + return partner.id + return False + + def get_from_label_and_partner_name(self, cr, uid, field_value, context=None): + """Match the partner based on the label field of the statement line + and the name of the partner.""" + supplier_ids = self.search(cr, uid, [['supplier', '=', True]], context=context) + sql = """SELECT id FROM res_partner WHERE name ilike """ + for partner in self.browse(cr, uid, supplier_ids, context=context): + if partner.name in label: + return partner.id + return False + + +class AccountStatementLine(Model): + """Add sparse field on the statement line to allow to store all the + bank infos that are given by an office. You can then add you own in your + module.""" + _inherit = "account.bank.statement.line" + + _columns={ + # 'email_address': fields.char('Email', size=64), + # 'order_ref': fields.char('Order Ref', size=64), + # 'partner_name': fields.char('Partner Name', size=64), + # + # Only label for a start, but other module can add their own + 'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', help="Used by completion and import system."), + 'label': fields.sparse(type='char', string='Label', + serialization_field='additionnal_bank_fields'), + + } + + + + def auto_complete_line(self, cr, uid, line, context=None): + res={} + if not line.partner_id or line.account_id.id ==1: + partner_obj = self.pool.get('res.partner') + partner_id=False + if line.order_ref: + partner_id = partner_obj.get_partner_from_order_ref(cr, uid, line.order_ref, context=context) + if not partner_id and line.email_address: + partner_id = partner_obj.get_partner_from_email(cr, uid, line.email_address, context=context) + if not partner_id and line.partner_name: + partner_id = partner_obj.get_partner_from_name(cr, uid, line.partner_name, context=context) + if not partner_id and line.label: + partner_id = partner_obj.get_partner_from_label_based_on_bank_statement_label(cr, uid, line.label, context=context) + if partner_id: + res = {'partner_id': partner_id} + if context['auto_completion']: + #Build the space for expr + space = { + 'self':self, + 'cr':cr, + 'uid':uid, + 'line': line, + 'res': res, + 'context':context, + } + exec context['auto_completion'] in space + if space.get('result', False): + res.update(space['result']) + return res + +class A(object): + def xx_toto(): + print 'toto' + + +a = A() +funcs = ['yy_toto', 'xx_toto'] +for i in funcs: + if hasattr(a, i): + to_call = getattr(a, i) + to_call() + else: + raise NameError('blblblb') + +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 entred. + """ + _inherit = "account.bank.statement" + + + def button_auto_completion(self, cr, uid, ids, context=None): + if not context: + context={} + stat_line_obj = self.pool.get('account.bank.statement.line') + for stat in self.browse(cr, uid, ids, context=context): + ctx = context.copy() + if stat.bank_statement_import_id: + ctx['partner_id'] = stat.bank_statement_import_id.partner_id.id + ctx['transferts_account_id'] = stat.bank_statement_import_id.transferts_account_id.id + ctx['credit_account_id'] = stat.bank_statement_import_id.credit_account_id.id + ctx['fee_account_id'] = stat.bank_statement_import_id.fee_account_id.id + ctx['auto_completion'] = stat.bank_statement_import_id.auto_completion + for line in stat.line_ids: + vals = stat_line_obj.auto_complete_line(cr, uid, line, context=ctx) + if not line.ref and not vals.get('ref', False): + vals['ref'] = stat.name + if vals: + stat_line_obj.write(cr, uid, line.id, vals, context=ctx) + return True + + def auto_confirm(self, cr, uid, ids, context=None): + if not context: + context={} + ok=True + for stat in self.browse(cr, uid, ids, context=context): + for line in stat.line_ids: + if not line.partner_id or line.account_id.id == 1: + ok=False + continue + if ok: + self.button_confirm(cr, uid, [stat.id], context=context) + return True diff --git a/account_statement_base_completion/statement_view.xml b/account_statement_base_completion/statement_view.xml new file mode 100644 index 00000000..0494d505 --- /dev/null +++ b/account_statement_base_completion/statement_view.xml @@ -0,0 +1,34 @@ + + + + + + account_bank_statement_import_base.bank_statement.view_form + account.bank.statement + + + form + + + + + + + + + 10 + + + +