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
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/account_statement_ext/wizard/__init__.py b/account_statement_base_import/__init__.py
similarity index 56%
rename from account_statement_ext/wizard/__init__.py
rename to account_statement_base_import/__init__.py
index 3d0490eb..f6c46966 100644
--- a/account_statement_ext/wizard/__init__.py
+++ b/account_statement_base_import/__init__.py
@@ -1,20 +1,22 @@
# -*- coding: utf-8 -*-
##############################################################################
#
-# Author Nicolas Bessi. Copyright Camptocamp SA
+# 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 General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
+# 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 General Public License for more details.
+# GNU Affero General Public License for more details.
#
-# You should have received a copy of the GNU General Public License
+# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see .
#
##############################################################################
-import import_statement
+
+import statement
\ No newline at end of file
diff --git a/account_statement_base_import/__openerp__.py b/account_statement_base_import/__openerp__.py
new file mode 100644
index 00000000..535c33db
--- /dev/null
+++ b/account_statement_base_import/__openerp__.py
@@ -0,0 +1,46 @@
+# -*- 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 easy import",
+ 'version': '1.0',
+ 'author': 'Camptocamp',
+ 'maintainer': 'Camptocamp',
+ 'category': 'Finance',
+ 'complexity': 'normal', #easy, normal, expert
+ 'depends': ['account_statement_ext','account_statement_base_completion'],
+ 'description': """
+ The goal of this module is bring basic method and fields on bank statement to deal with
+ the importation of different bank and offices.
+
+
+ """,
+ 'website': 'http://www.camptocamp.com',
+ 'init_xml': [],
+ 'update_xml': [
+ ],
+ 'demo_xml': [],
+ 'test': [],
+ 'installable': True,
+ 'images': [],
+ 'auto_install': False,
+ 'license': 'AGPL-3',
+ 'active': False,
+}
diff --git a/account_statement_base_import/statement.py b/account_statement_base_import/statement.py
new file mode 100644
index 00000000..ebb6f11c
--- /dev/null
+++ b/account_statement_base_import/statement.py
@@ -0,0 +1,81 @@
+# -*- 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 .
+#
+##############################################################################
+
+from tools.translate import _
+import datetime
+import netsvc
+logger = netsvc.Logger()
+from openerp.osv.orm import Model, fields
+
+
+class AccountStatementProfil(Model):
+ _inherit = "account.statement.profil"
+
+ _columns = {
+ 'launch_import_completion': fields.boolean("Launch completion after import",
+ help="Tic that box to automatically launch the completion on each imported\
+ file using this profile."),
+ 'last_import_date': fields.date("Last Import Date"),
+ 'rec_log': fields.text('log', readonly=True),
+
+ }
+
+ def launch_import_bank_statement(self, cr, uid, ids, context=None):
+ stat_obj = self.pool.get('account.bank.statement')
+ for id in ids:
+ logger = netsvc.Logger()
+ res = self.action_import_bank_statement(cr, uid, id, conteaccount_xt)
+ #autocomplete bank statement
+ stat_obj.button_auto_completion(cr, uid, res['crids'], context=context)
+ stat_obj.auto_confirm(cr, uid, res['crids'], context=context)
+ log = self.read(cr, uid, id, ['rec_log'], context=context)['rec_log']
+ log_line = log and log.split("\n") or []
+ log_line[0:0] = [datetime.now().strftime('%Y-%m-%d %H:%M:%S') + ' : ' + str(len(res['crids'])) + _(' bank statement have been imported and ' + str(len(res['exist_ids'])) + _(' bank statement already exist'))]
+ log = "\n".join(log_line)
+ self.write(cr, uid, id, {'rec_log' : log}, context=context)
+ logger.notifyChannel('banck statement import', netsvc.LOG_INFO, "%s bank statement have been imported and %s bank statement already exist"%(len(res['crids']), len(res['exist_ids'])))
+ return True
+
+ def action_import_bank_statement(self, cr, uid, id, context=None):
+ '''not implemented in this module'''
+ return {}
+
+ def open_bank_statement(self, cr, uid, ids, context):
+ task = self.browse(cr, uid, ids, context=context)[0]
+
+ return {
+ 'name': 'Bank ',
+ 'view_type': 'form',
+ 'view_mode': 'form',
+ 'view_id': [252],
+ 'res_model': self._name,
+ 'type': 'ir.actions.act_window',
+ 'nodestroy': True,
+ 'target': 'current',
+ 'res_id': self.read(cr, uid, ids, ['bank_statement_ids'],context=context)[0]['bank_statement_ids'],
+ }
+
+class AccountBankSatement(Model):
+
+ _inherit = "account.bank.statement"
+
+
+
diff --git a/account_statement_base_import/statement_view.xml b/account_statement_base_import/statement_view.xml
new file mode 100644
index 00000000..508aeb9c
--- /dev/null
+++ b/account_statement_base_import/statement_view.xml
@@ -0,0 +1,47 @@
+
+
+
+
+
+
+ account.statement.profil.view
+ account.statement.profil
+
+ form
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/account_statement_ext/__init__.py b/account_statement_ext/__init__.py
index c421ad5b..701622aa 100644
--- a/account_statement_ext/__init__.py
+++ b/account_statement_ext/__init__.py
@@ -23,3 +23,4 @@ import file_parser
import wizard
import statement
import report
+import account
\ No newline at end of file
diff --git a/account_statement_ext/__openerp__.py b/account_statement_ext/__openerp__.py
index 5d65ad90..98cd29dc 100644
--- a/account_statement_ext/__openerp__.py
+++ b/account_statement_ext/__openerp__.py
@@ -27,15 +27,16 @@
'complexity': 'normal', #easy, normal, expert
'depends': ['base_transaction_id'],
'description': """
- The goal of this module is to help dealing with huge volume of reconciliation through
- payment offices like Paypal, Lazer, Visa, Amazon and so on. It's mostly used for
- E-commerce but can be usefule for other use cases as it introduce a notion of profil
- on the bank statement to have more control on the generated entries.
+ The goal of this module is to improve the basic bank statement, help dealing with huge volume of
+ reconciliation through payment offices like Paypal, Lazer, Visa, Amazon and so on.
+
+ It will be mostly used for E-commerce but can be usefule for other use cases as it introduce a
+ notion of profil on the bank statement to have more control on the generated entries. It will
+ be the base for all new features developped to improve the reconciliation process.
Features:
- 1) This module improves the bank statement that allow and you to import your bank transactions with
- a standard .csv or .xls file (you'll find it in the 'data' folder). You can now define profile for each
+ 1) This module improves the bank statement that allow and you to define profile for each
Office or Bank that will generate the entries based on some criteria. You can setup:
- Account commission and partner relation
@@ -51,15 +52,19 @@
4) Remove the period on the bank statement, and compute it for each line based on their date instead.
- 5) Provide a standard import format to create and fullfill a bank statement from a .csv or .xls file. For
+ 5) Cancelling a bank statement is much more easy and will cancel all related entries, unreconcile them,
+ and finally delete it.
+
+ 6) Add the ID in entries view so that you can easily filter on a statement ID to reconcile all related
+ entries at once (e.g. one statement (ID 100) for paypal on an intermediate account, and then another for
+ the bank on the bank account. You can then manually reconcile all the line from the first one with
+ one line of the second by finding them through the statement ID.)
-
""",
'website': 'http://www.camptocamp.com',
'init_xml': [],
'update_xml': [
'statement_view.xml',
- 'wizard/import_statement_view.xml',
'report/bank_statement_webkit_header.xml',
'report.xml',
],
diff --git a/account_statement_ext/account.py b/account_statement_ext/account.py
new file mode 100644
index 00000000..01886734
--- /dev/null
+++ b/account_statement_ext/account.py
@@ -0,0 +1,38 @@
+# -*- 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 netsvc
+logger = netsvc.Logger()
+from openerp.osv.orm import Model, fields
+
+class account_move(osv.osv):
+ _inherit='account.move'
+
+ def unlink(self, cr, uid, ids, context=None):
+ """Delete the reconciliation when we delete the moves. This
+ allow an easier way of cancelling the bank statement."""
+ for move in self.browse(cr, uid, ids, context=context):
+ for move_line in move.line_id:
+ if move_line.reconcile_id:
+ move_line.reconcile_id.unlink(context=context)
+ return super(account_move, self).unlink(cr, uid, ids, context=context)
+account_move()
+
+
diff --git a/account_statement_ext/datas/statement.csv b/account_statement_ext/datas/statement.csv
deleted file mode 100644
index 491df223..00000000
--- a/account_statement_ext/datas/statement.csv
+++ /dev/null
@@ -1,4 +0,0 @@
-"transaction_id";"date";"amount";"commission_amount";"label"
-50969286;2011-03-07 13:45:14;118.4;-11.84;"label a"
-51065326;2011-03-05 13:45:14;189;-15.12;"label b"
-51179306;2011-03-02 17:45:14;189;-15.12;"label c"
diff --git a/account_statement_ext/datas/statement.xls b/account_statement_ext/datas/statement.xls
deleted file mode 100644
index 13eeafee..00000000
Binary files a/account_statement_ext/datas/statement.xls and /dev/null differ
diff --git a/account_statement_ext/file_parser/parser.py b/account_statement_ext/file_parser/parser.py
deleted file mode 100644
index 9d11aa51..00000000
--- a/account_statement_ext/file_parser/parser.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# -*- coding: utf-8 -*-
-##############################################################################
-#
-# Copyright Camptocamp SA
-# Author Nicolas Bessi
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU 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 General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program. If not, see .
-#
-##############################################################################
-
-"""
-Parser for csv or xml for file containing credit transfert data from
-financial institure as VISA
-"""
-
-from tools.translate import _
-import base64
-import csv
-import tempfile
-import datetime
-try:
- import xlrd
-except:
- raise Exception(_('Please install python lib xlrd'))
-
-def UnicodeDictReader(utf8_data, **kwargs):
- csv_reader = csv.DictReader(utf8_data, **kwargs)
- for row in csv_reader:
- yield dict([(key, unicode(value, 'utf-8')) for key, value in row.iteritems()])
-
-# TODO extract into a lib helper module
-class FileParser(object):
- def __init__(self, filebuffer, keys_to_validate=None, decode_base_64=True, ftype='csv'):
- if ftype in ('csv', 'xls'):
- self.ftype = ftype
- else:
- raise Exception(_('Invalide file type %s. please use csv or xls') % (ftype))
- self.keys_to_validate = keys_to_validate
- self.decode_base_64 = decode_base_64
- if filebuffer:
- self.filebuffer = filebuffer
- else:
- raise Exception(_('No buffer file'))
-
- def parse(self):
- "launch parsing of csv or xls"
- if self.decode_base_64:
- self._decode_64b_stream()
- res = None
- if self.ftype == 'csv':
- res = self.parse_csv()
- else:
- res = self.parse_xls()
- if self.keys_to_validate:
- self._validate_column(res, self.keys_to_validate)
- return res
-
- def _decode_64b_stream(self):
- self.filebuffer = base64.b64decode(self.filebuffer)
- return self.filebuffer
-
- def _validate_column(self, array_of_dict, cols):
- parsed_cols = array_of_dict[0].keys()
- for col in cols:
- if col not in parsed_cols:
- raise Exception(_('col %s not present in file') % (col))
-
- def parse_csv(self, delimiter=';'):
- "return an array of dict from csv file"
- csv_file = tempfile.NamedTemporaryFile()
- csv_file.write(self.filebuffer)
- # We ensure that cursor is at beginig of file
- csv_file.seek(0)
- reader = UnicodeDictReader(
- open(csv_file.name).readlines(),
- delimiter=delimiter
- )
- return [x for x in reader]
-
- def parse_xls(self):
- "return an array of dict from csv file"
- wb_file = tempfile.NamedTemporaryFile()
- wb_file.write(self.filebuffer)
- # We ensure that cursor is at beginig of file
- wb_file.seek(0)
- wb = xlrd.open_workbook(wb_file.name)
- sheet = wb.sheet_by_index(0)
- header = sheet.row_values(0)
- res = []
- for rownum in range(1, sheet.nrows):
- res.append(dict(zip(header, sheet.row_values(rownum))))
- try:
- wb_file.close()
- except Exception, e:
- pass #file is allready closed
- return res
-
- def _from_csv(self, result_set, conversion_rules):
- for line in result_set:
- for rule in conversion_rules:
- if conversion_rules[rule] == datetime.datetime:
- date_string = line[rule].split(' ')[0]
- line[rule] = datetime.datetime.strptime(date_string,
- '%Y-%m-%d')
- else:
- line[rule] = conversion_rules[rule](line[rule])
- return result_set
-
- def _from_xls(self, result_set, conversion_rules):
- for line in result_set:
- for rule in conversion_rules:
- if conversion_rules[rule] == datetime.datetime:
- t_tuple = xlrd.xldate_as_tuple(line[rule], 1)
- line[rule] = datetime.datetime(*t_tuple)
- else:
- line[rule] = conversion_rules[rule](line[rule])
- return result_set
-
- def cast_rows(self, result_set, conversion_rules):
- func = getattr(self, '_from_%s'%(self.ftype))
- return func(result_set, conversion_rules)
diff --git a/account_statement_ext/statement.py b/account_statement_ext/statement.py
index 5fba0b19..87159a17 100644
--- a/account_statement_ext/statement.py
+++ b/account_statement_ext/statement.py
@@ -27,13 +27,16 @@ logger = netsvc.Logger()
from openerp.osv.orm import Model, fields
class AccountStatementProfil(Model):
+ """A Profile will contain all infos related to the type of
+ bank statement, and related generated entries. It define the
+ journal to use, the partner and commision account and so on."""
_name = "account.statement.profil"
_description = "Statement Profil"
_columns = {
'name': fields.char('Name', size=128, required=True),
'partner_id': fields.many2one('res.partner',
- 'Credit insitute partner',
+ 'Bank/Payment Office partner',
help="Put a partner if you want to have it on the commission move (and optionaly\
on the counterpart of the intermediate/banking move if you tic the corresponding checkbox)."),
'journal_id': fields.many2one('account.journal',
@@ -57,6 +60,10 @@ class AccountStatementProfil(Model):
help="Tic that box if you want OpenERP to control the start/end balance\
before confirming a bank statement. If don't ticked, no balance control will be done."
),
+ 'bank_statement_prefix': fields.char('Bank Statement Prefix', size=32),
+ 'bank_statement_ids': fields.one2many('account.bank.statement', 'profile_id', 'Bank Statement Imported'),
+
+
}
_defaults = {}
@@ -73,43 +80,40 @@ class AccountStatementProfil(Model):
class AccountBankSatement(Model):
- """A kind of bank statement for intermediate move between customer and real bank, used
- for manageing check, payment office like paypal or marketplace like amazon.
- We inherit account.bank.statement because it's a very close object with only some
- difference. But we want some method to be completely different, so we create a new object."""
+ """We improve the bank statement class mostly for :
+ - Removing the period and compute it from the date of each line.
+ - Allow to remove the balance check depending on the chosen profil
+ - Report errors on confirmation all at once instead of crashing onr by one
+ - Add a profil notion that can change the generated entries on statement
+ confirmation.
+ For this, we'll had to override quite some long method and we'll need to maintain
+ them up to date. Changes are point up by '#Chg' comment."""
_inherit = "account.bank.statement"
_columns = {
- 'import_config_id': fields.many2one('account.statement.profil',
+ 'profile_id': fields.many2one('account.statement.profil',
'Profil', required=True, states={'draft': [('readonly', False)]}),
'credit_partner_id': fields.related(
- 'import_config_id',
+ 'profile_id',
'partner_id',
type='many2one',
relation='res.partner',
string='Financial Partner',
store=True, readonly=True),
'balance_check': fields.related(
- 'import_config_id',
+ 'profile_id',
'balance_check',
type='boolean',
string='Balance check',
store=True, readonly=True),
'journal_id': fields.related(
- 'import_config_id',
+ 'profile_id',
'journal_id',
type='many2one',
relation='account.journal',
string='Journal',
store=True, readonly=True),
- # 'line_ids': fields.one2many('account.bank.statement.line',
- # 'statement_id', 'Statement lines',
- # states={'confirm':[('readonly', True)]}),
- # 'move_line_ids': fields.one2many('account.move.line', 'statement_treasury_id',
- # 'Entry lines', states={'confirm':[('readonly',True)]}),
- # Redefine this field to avoid his computation (it is a function field on bank statement)
- # 'balance_end': fields.dummy(string="Computed Balance"),
'period_id': fields.many2one('account.period', 'Period', required=False, readonly=True),
}
@@ -120,15 +124,15 @@ class AccountBankSatement(Model):
def create(self, cr, uid, vals, context=None):
"""Need to pass the journal_id in vals anytime because of account.cash.statement
that need it."""
- if 'import_config_id' in vals:
+ if 'profile_id' in vals:
profil_obj = self.pool.get('account.statement.profil')
- profile = profil_obj.browse(cr,uid,vals['import_config_id'],context)
+ profile = profil_obj.browse(cr,uid,vals['profile_id'],context)
vals['journal_id'] = profile.journal_id.id
return super(AccountBankSatement, self).create(cr, uid, vals, context=context)
def _get_period(self, cursor, uid, date, context=None):
'''
- Find matching period for date, used in thestatement line creation.
+ Find matching period for date, used in the statement line creation.
'''
period_obj = self.pool.get('account.period')
periods = period_obj.find(cursor, uid, dt=date, context=context)
@@ -154,6 +158,22 @@ class AccountBankSatement(Model):
(_check_company_id, 'The journal and period chosen have to belong to the same company.', ['journal_id','period_id']),
]
+ def button_cancel(self, cr, uid, ids, context={}):
+ """We cancel the related move, delete them and finally put the
+ statement in draft state."""
+ done = []
+ for st in self.browse(cr, uid, ids, context=context):
+ if st.state=='draft':
+ continue
+ ids = []
+ for line in st.line_ids:
+ for move in line.move_ids:
+ move.button_cancel(context=context)
+ move.unlink(context=context)
+ done.append(st.id)
+ self.write(cr, uid, done, {'state':'draft'}, context=context)
+ return True
+
def create_move_from_st_line(self, cr, uid, st_line_id, company_currency_id, st_line_number, context=None):
"""Override a large portion of the code to compute the periode for each line instead of
taking the period of the whole statement.
@@ -165,7 +185,7 @@ class AccountBankSatement(Model):
- If partner_id is set, we'll us it for the commission (when imported throufh the wizard)
- If partner_id is set and force_partner_on_bank is ticked, we'll let the partner of each line
for the debit line, but we'll change it on the credit move line for the choosen partner_id
- => This will ease the reconsiliation process with the bank as the partner will match the bank
+ => This will ease the reconciliation process with the bank as the partner will match the bank
statement line
"""
if context is None:
@@ -246,8 +266,8 @@ class AccountBankSatement(Model):
amount_currency = st_line.amount
currency_id = st.currency.id
# GET THE RIGHT PARTNER ACCORDING TO THE CHOSEN PROFIL # Chg
- if st.import_config_id.force_partner_on_bank: # Chg
- bank_parrtner_id = st.import_config_id.partner_id.id # Chg
+ if st.profile_id.force_partner_on_bank: # Chg
+ bank_parrtner_id = st.profile_id.partner_id.id # Chg
else: # Chg
bank_parrtner_id = ((st_line.partner_id) and st_line.partner_id.id) or False # Chg
@@ -280,16 +300,19 @@ class AccountBankSatement(Model):
account_move_obj.post(cr, uid, [move_id], context=context)
return move_id
- def _get_st_number_period(self, cr, uid, date, journal_sequence_id):
+ def _get_st_number_period_profil(self, cr, uid, date, profile_id, journal_sequence_id):
"""Retrieve the name of bank statement from sequence, according to the period
- corresponding to the date passed in args"""
+ corresponding to the date passed in args. Add a prefix if set in the profil."""
year = self.pool.get('account.period').browse(cr, uid, self._get_period(cr, uid, date)).fiscalyear_id.id
+ profile = self.pool.get('account.statement.profil').browse(cr,uid, profile_id)
c = {'fiscalyear_id': year}
obj_seq = self.pool.get('ir.sequence')
if journal_sequence_id:
st_number = obj_seq.next_by_id(cr, uid, journal_sequence_id, context=c)
else:
st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
+ if profile.bank_statement_prefix:
+ st_number = profile.bank_statement_prefix + st_number
return st_number
def button_confirm_bank(self, cr, uid, ids, context=None):
@@ -319,12 +342,7 @@ class AccountBankSatement(Model):
else:
# Begin Changes
seq_id = st.journal_id.sequence_id and st.journal_id.sequence_id.id or False
- st_number = self._get_st_number_period(cr, uid, st.date, seq_id)
- # c = {'fiscalyear_id': st.period_id.fiscalyear_id.id}
- # if st.journal_id.sequence_id:
- # st_number = obj_seq.next_by_id(cr, uid, st.journal_id.sequence_id.id, context=c)
- # else:
- # st_number = obj_seq.next_by_code(cr, uid, 'account.bank.statement', context=c)
+ st_number = self._get_st_number_period_profil(cr, uid, st.date, st.profile_id.id, seq_id)
# End Changes
for line in st.move_line_ids:
if line.state <> 'valid':
@@ -359,24 +377,30 @@ class AccountBankSatement(Model):
self.log(cr, uid, st.id, _('Statement %s is confirmed, journal items are created.') % (st_number,))
return self.write(cr, uid, ids, {'state':'confirm'}, context=context)
- def get_partner_from_so(self, cursor, uid,transaction_id):
- """Look for the SO that has the given transaction_id, if not
- found, try to match the SO name instead. If still nothing,
- return False"""
- so_obj = self.pool.get('sale.order')
- so_id = so_obj.search(cursor, uid, [('transaction_id', '=', transaction_id)])
- if so_id and len(so_id) == 1:
- return so_obj.browse(cursor, uid, so_id[0]).partner_id.id
+ def get_account_for_counterpart(self, cursor, uid,
+ amount, account_receivable, account_payable):
+ """Give the amount, payable and receivable account (that can be found using
+ get_default_pay_receiv_accounts).
+ Return the default account to be used by statement line as the counterpart
+ of the journal account depending on the amount"""
+ account_id = False
+ if amount >= 0:
+ account_id = account_receivable
else:
- so_id2 = so_obj.search(cursor, uid, [('name', '=', transaction_id)])
- if so_id2 and len(so_id2) == 1:
- return so_obj.browse(cursor, uid, so_id2[0]).partner_id.id
- return False
+ account_id = account_payable
+ if not account_id:
+ raise osv.except_osv(
+ _('Can not determine account'),
+ _('Please ensure that minimal properties are set')
+ )
+ return account_id
-
- def get_default_accounts(self, cursor, uid, receivable_account_id, context=None):
- """We try to determine default accounts if not receivable_account_id set, otherwise
- take it for both receivable and payable account"""
+ def get_default_pay_receiv_accounts(self, cursor, uid, receivable_account_id, context=None):
+ """We try to determine default payable/receivable accounts to be used as counterpart
+ of the journal one.
+
+ If receivable_account_id is set (from the profil), take it as receivable/payable
+ account. Otherwise take it from the property of the partner."""
account_receivable = False
account_payable = False
if receivable_account_id:
@@ -410,21 +434,6 @@ class AccountBankSatement(Model):
account_payable = erp_property.value_reference.id
return account_receivable, account_payable
- def _get_account_id(self, cursor, uid,
- amount, account_receivable, account_payable):
- "return the default account to be used by statement line"
- account_id = False
- if amount >= 0:
- account_id = account_receivable
- else:
- account_id = account_payable
- if not account_id:
- raise osv.except_osv(
- _('Can not determine account'),
- _('Please ensure that minimal properties are set')
- )
- return account_id
-
def balance_check(self, cr, uid, st_id, journal_type='bank', context=None):
"""Balance check depends on the profil. If no check for this profil is required,
return True"""
@@ -433,25 +442,11 @@ class AccountBankSatement(Model):
return super(AccountBankSatement,self).balance_check(cr, uid, st_id, journal_type, context)
else:
return True
-
- def _get_value_from_import_config(self, cr, uid, import_config_id):
- """Return a dict with with values taken from the given config.
- e.g. (journal_id, partner_id, commission_account_id, mode, forced_account_id)
- """
- # Get variable from config
- import_config = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
- forced_account_id = import_config.receivable_account_id and import_config.receivable_account_id.id or False
- journal_id = import_config.journal_id and import_config.journal_id.id or False
- partner_id = import_config.partner_id and import_config.partner_id.id or False
- commission_account_id = import_config.commission_account_id.id
- commission_analytic_id = import_config.commission_analytic_id and import_config.commission_analytic_id.id or False
- force_partner_on_bank = import_config.force_partner_on_bank
- return journal_id, partner_id, commission_account_id, commission_analytic_id, forced_account_id, force_partner_on_bank
- def onchange_imp_config_id(self, cr, uid, ids, import_config_id, context=None):
- if not import_config_id:
+ def onchange_imp_config_id(self, cr, uid, ids, profile_id, context=None):
+ if not profile_id:
return {}
- import_config = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
+ import_config = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
journal_id = import_config.journal_id.id
account_id = import_config.journal_id.default_debit_account_id.id
credit_partner_id = import_config.partner_id and import_config.partner_id.id or False
@@ -460,132 +455,6 @@ class AccountBankSatement(Model):
'credit_partner_id':credit_partner_id,
}}
- def credit_statement_import(self, cursor, uid, ids,
- import_config_id,
- file_stream,
- ftype="csv",
- context=None):
- "Create statement from file stream encoded in base 64"
- context = context or {}
- statement_obj = self.pool.get('account.bank.statement')
- statement_line_obj = self.pool.get('account.bank.statement.line')
- attachment_obj = self.pool.get('ir.attachment')
-
- # Get variable from config
- journal_id, partner_id, commission_account_id, commission_analytic_id, \
- forced_account_id, force_partner_on_bank = self._get_value_from_import_config(cursor,uid,import_config_id)
-
- account_receivable, account_payable = self.get_default_accounts(cursor, uid, forced_account_id)
-
- ##Order of cols does not matter but first row has to be header
- keys = ['transaction_id', 'label', 'date', 'amount', 'commission_amount']
- #required_values = ['transaction_id', 'amount', 'commission_amount']
- convertion_dict = {
- 'transaction_id': unicode,
- 'label': unicode,
- 'date': datetime.datetime,
- 'amount': float,
- 'commission_amount': float
- }
-
- f_parser = FileParser(file_stream,
- keys_to_validate=keys,
- decode_base_64=True,
- ftype=ftype)
- statement_lines = f_parser.parse()
- statement_lines = f_parser.cast_rows(statement_lines, convertion_dict)
- journal = self.pool.get('account.journal').browse(cursor, uid, journal_id)
- statement_id = statement_obj.create(cursor,
- uid,
- { 'import_config_id':import_config_id,
- 'journal_id': journal_id,
- 'journal_id': journal_id,
- 'credit_partner_id': partner_id,
- 'statement_type': 'credit_partner',
- },
- context)
- commission_global_amount = 0.0
- if not journal.default_debit_account_id \
- or not journal.default_credit_account_id:
- raise osv.except_osv(
- _("Missing default account on journal %s")%(journal.name),
- _("Please correct the journal"))
- try:
- for line in statement_lines:
- line_partner_id = False
- line_to_reconcile = False
- # We ensure that required values of the line are set
-# for val in required_values:
-# if not line.get(val, False) and line.get(val, False) != 0.0:
-# raise osv.except_osv(
-# _("Field %s not set for line %s")%(str(line),),
-# _("Please correct the file"))
-
- commission_global_amount += line.get('commission_amount', 0.0)
- values = {
- 'name': "IN %s %s"%(line['transaction_id'],
- line.get('label', '')),
- 'date': line.get('date', datetime.datetime.now().date()),
- 'amount': line['amount'],
- 'ref': "TID_%s"%(line['transaction_id'],),
- 'type': 'customer',
- 'statement_id': statement_id,
- #'account_id': journal.default_debit_account_id
- }
- values['account_id'] = self._get_account_id(
- cursor,
- uid,
- line['amount'],
- account_receivable,
- account_payable
- )
- if not line_partner_id:
- line_partner_id = self.get_partner_from_so(cursor,
- uid, line['transaction_id'])
- values['partner_id'] = line_partner_id
- # we finally create the line in system
- statement_line_obj.create(cursor, uid, values, context=context)
-
- # we create commission line
- if commission_global_amount:
- comm_values = {
- 'name': 'IN '+ _('Commission line'),
- 'date': datetime.datetime.now().date(),
- 'amount': commission_global_amount,
- 'partner_id': partner_id,
- 'type': 'general',
- 'statement_id': statement_id,
- 'account_id': commission_account_id,
- 'ref': 'commission',
- 'analytic_account_id': commission_analytic_id
- }
- statement_line_obj.create(cursor, uid,
- comm_values,
- context=context)
-
- attachment_obj.create(
- cursor,
- uid,
- {
- 'name': 'statement file',
- 'datas': file_stream,
- 'datas_fname': "%s.%s"%(datetime.datetime.now().date(),
- ftype),
- 'res_model': 'account.bank.statement',
- 'res_id': statement_id,
- },
- context=context
- )
- except Exception, exc:
- logger.notifyChannel("Statement import",
- netsvc.LOG_ERROR,
- _("Statement can not be created %s") %(exc,))
-
- statement_obj.unlink(cursor, uid, [statement_id])
- raise exc
- return statement_id
-
-
class AccountBankSatementLine(Model):
_inherit = "account.bank.statement.line"
@@ -596,11 +465,7 @@ class AccountBankSatementLine(Model):
return periods and periods[0] or False
_columns = {
- # 'statement_id': fields.many2one('account.bank.statement', 'Statement',
- # select=True, required=True, ondelete='cascade'),
- # 'move_ids': fields.many2many('account.move',
- # 'account_treasury_statement_line_move_rel', 'statement_line_id','move_id',
- # 'Moves'),
+ # Set them as required
'ref': fields.char('Reference', size=32, required=True),
'period_id': fields.many2one('account.period', 'Period', required=True),
}
@@ -608,18 +473,11 @@ class AccountBankSatementLine(Model):
'period_id': _get_period,
}
- # WARNING => Crash cause the super method here calls onchange_type => and then
- # we don't call it from the good model.... => We'll need to override the complete method here
- def onchange_partner_id(self, cr, uid, ids, partner_id, import_config_id, context=None):
- # import pdb;pdb.set_trace()
- # if context is None:
- # context = {}
- # res = super(AccountTreasurySatementLine,self).onchange_partner_id(cr, uid, ids, partner_id, context)
- # c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
- # acc_id=c.receivable_account_id and c.receivable_account_id.id or False
- # if acc_id:
- # res['value'].update({'account_id':acc_id})
- # return res
+
+
+ def onchange_partner_id(self, cr, uid, ids, partner_id, profile_id, context=None):
+ """When changing the partner, we'll now need to look in the profil to determine which
+ account to use."""
obj_partner = self.pool.get('res.partner')
if context is None:
context = {}
@@ -635,34 +493,26 @@ class AccountBankSatementLine(Model):
type = 'supplier'
if part.customer == True:
type = 'customer'
- res_type = self.onchange_type(cr, uid, ids, partner_id, type, import_config_id, context=context)
+ res_type = self.onchange_type(cr, uid, ids, partner_id, type, profile_id, context=context)
if res_type['value'] and res_type['value'].get('account_id', False):
res = {'value': {'type': type, 'account_id': res_type['value']['account_id']}}
else:
res = {'value': {'type': type}}
- c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
+ c = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
acc_id=c.receivable_account_id and c.receivable_account_id.id or False
if acc_id:
res['value'].update({'account_id':acc_id})
return res
- # TOFIX
- def onchange_type(self, cr, uid, line_id, partner_id, type, import_config_id, context=None):
+ # TOFIX: don't seems to work as expected
+ def onchange_type(self, cr, uid, line_id, partner_id, type, profile_id, context=None):
if context is None:
context = {}
res = super(AccountBankSatementLine,self).onchange_type(cr, uid, line_id, partner_id, type, context)
- c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
+ c = self.pool.get("account.statement.profil").browse(cr,uid,profile_id)
acc_id=c.receivable_account_id and c.receivable_account_id.id or False
if acc_id:
res['value'].update({'account_id':acc_id})
return res
-# class AccountMoveLine(Model):
-# _inherit = "account.move.line"
-#
-# _columns = {
-# 'statement_treasury_id': fields.many2one('account.bank.statement', 'Statement', help="The intermediate statement used for reconciliation", select=1),
-# }
-
-
diff --git a/account_statement_ext/statement_view.xml b/account_statement_ext/statement_view.xml
index 0ea59c0a..eb5f94a7 100644
--- a/account_statement_ext/statement_view.xml
+++ b/account_statement_ext/statement_view.xml
@@ -40,6 +40,7 @@
+
@@ -90,7 +91,7 @@
search
-
+
@@ -109,7 +110,7 @@
tree
-
+
@@ -133,7 +134,7 @@
-
+
@@ -166,23 +167,23 @@
-
+
-
+
-
+
-
+
-
+
diff --git a/account_statement_ext/wizard/import_statement.py b/account_statement_ext/wizard/import_statement.py
deleted file mode 100644
index 6c53f804..00000000
--- a/account_statement_ext/wizard/import_statement.py
+++ /dev/null
@@ -1,107 +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 .
-#
-##############################################################################
-
-"""
-Wizard to import financial institute date in bank statement
-"""
-
-from osv import fields, osv
-from tools.translate import _
-import os
-
-class CreditPartnerStatementImporter(osv.osv_memory):
- """Import Credit statement"""
-
- _name = "credit.statement.import"
- _description = __doc__
- _columns = {
-
- 'import_config_id': fields.many2one('account.statement.profil',
- 'Import configuration parameter',
- required=True),
- 'partner_id': fields.many2one('res.partner',
- 'Credit insitute partner',
- ),
- 'journal_id': fields.many2one('account.journal',
- 'Financial journal to use transaction',
- ),
- 'input_statement': fields.binary('Statement file', required=True),
- 'file_name': fields.char('File Name', size=128),
- 'commission_account_id': fields.many2one('account.account',
- 'Commission account',
- ),
- 'commission_analytic_id': fields.many2one('account.analytic.account',
- 'Commission analytic account',
- ),
- 'receivable_account_id': fields.many2one('account.account',
- 'Force Receivable/Payable Account'),
- 'force_partner_on_bank': fields.boolean('Force partner on bank move',
- help="Tic that box if you want to use the credit insitute partner\
- in the counterpart of the treasury/banking move."
- ),
- 'balance_check': fields.boolean('Balance check',
- help="Tic that box if you want OpenERP to control the start/end balance\
- before confirming a bank statement. If don't ticked, no balance control will be done."
- ),
-
- }
-
- def onchange_import_config_id(self, cr, uid, ids, import_config_id, context=None):
- res={}
- if import_config_id:
- c = self.pool.get("account.statement.profil").browse(cr,uid,import_config_id)
- res = {'value': {'partner_id': c.partner_id and c.partner_id.id or False,
- 'journal_id': c.journal_id and c.journal_id.id or False, 'commission_account_id': \
- c.commission_account_id and c.commission_account_id.id or False,
- 'receivable_account_id': c.receivable_account_id and c.receivable_account_id.id or False,
- 'commission_a':c.commission_analytic_id and c.commission_analytic_id.id or False,
- 'force_partner_on_bank':c.force_partner_on_bank,
- 'balance_check':c.balance_check,}}
- return res
-
- def import_statement(self, cursor, uid, req_id, context=None):
- """This Function import credit card agency statement"""
- context = context or {}
- if isinstance(req_id, list):
- req_id = req_id[0]
- importer = self.browse(cursor, uid, req_id, context)
- (shortname, ftype) = os.path.splitext(importer.file_name)
- if not ftype:
- #We do not use osv exception we do not want to have it logged
- raise Exception(_('Please use a file with an extention'))
- sid = self.pool.get(
- 'account.bank.statement').credit_statement_import(
- cursor,
- uid,
- False,
- importer.import_config_id.id,
- importer.input_statement,
- ftype.replace('.',''),
- context=context
- )
- obj_data = self.pool.get('ir.model.data')
- act_obj = self.pool.get('ir.actions.act_window')
- result = obj_data.get_object_reference(cursor, uid, 'account_statement_import', 'action_treasury_statement_tree')
-
- id = result and result[1] or False
- result = act_obj.read(cursor, uid, [id], context=context)[0]
- result['domain'] = str([('id','in',[sid])])
- return result
diff --git a/account_statement_ext/wizard/import_statement_view.xml b/account_statement_ext/wizard/import_statement_view.xml
deleted file mode 100644
index 77d2dd25..00000000
--- a/account_statement_ext/wizard/import_statement_view.xml
+++ /dev/null
@@ -1,44 +0,0 @@
-
-
-
-
- credit.statement.import.config.view
- credit.statement.import
- form
-
-
-
-
-
-
- Import statement
- credit.statement.import
- form
- tree,form
-
- new
-
-
-
-
-
-
diff --git a/account_statement_transactionid_completion/__init__.py b/account_statement_transactionid_completion/__init__.py
new file mode 100644
index 00000000..a8ce7c24
--- /dev/null
+++ b/account_statement_transactionid_completion/__init__.py
@@ -0,0 +1,22 @@
+# -*- 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
diff --git a/account_statement_transactionid_completion/__openerp__.py b/account_statement_transactionid_completion/__openerp__.py
new file mode 100644
index 00000000..79671cb1
--- /dev/null
+++ b/account_statement_transactionid_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 completion from transaction ID",
+ 'version': '1.0',
+ 'author': 'Camptocamp',
+ 'maintainer': 'Camptocamp',
+ 'category': 'Finance',
+ 'complexity': 'normal', #easy, normal, expert
+ 'depends': ['base_transaction_id','account_statement_base_completion'],
+ 'description': """
+ Add a completion method based on transaction ID providen by the bank/office. This
+ transaction ID has been recorded on the SO (by a mapping through the e-commerce connector,
+ or manually). Completion will look in the SO with that transaction ID to match the partner.
+
+ """,
+ '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_transactionid_completion/statement.py b/account_statement_transactionid_completion/statement.py
new file mode 100644
index 00000000..cea4fece
--- /dev/null
+++ b/account_statement_transactionid_completion/statement.py
@@ -0,0 +1,51 @@
+# -*- 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 .
+#
+##############################################################################
+
+from tools.translate import _
+import datetime
+import netsvc
+logger = netsvc.Logger()
+from openerp.osv.orm import Model, fields
+
+
+class AccountStatementProfil(Model):
+ _inherit = "account.statement.profil"
+
+
+class AccountBankSatement(Model):
+
+ _inherit = "account.bank.statement"
+
+class AccountStatementLine(Model):
+ _inherit = "account.bank.statement.line"
+
+ _columns={
+ # 'additionnal_bank_fields' : fields.serialized('Additionnal infos from bank', help="Used by completion and import system."),
+ 'transaction_id': fields.sparse(type='char', string='Transaction ID',
+ size=128,
+ serialization_field='additionnal_bank_fields',
+ help="Transction id from the financial institute"),
+ }
+
+
+
+
+
diff --git a/account_statement_transactionid_completion/statement_view.xml b/account_statement_transactionid_completion/statement_view.xml
new file mode 100644
index 00000000..9a26048f
--- /dev/null
+++ b/account_statement_transactionid_completion/statement_view.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+ account_bank_statement_import_base.bank_statement.view_form
+ account.bank.statement
+
+
+ form
+
+
+
+
+
+
+
+
+
+
+
+