[IMP] generic wizard to import bank statements + import of OFX and QIF files (+adapte...
authorqdp-odoo <qdp@openerp.com>
Fri, 1 Aug 2014 13:00:18 +0000 (15:00 +0200)
committerqdp-odoo <qdp@openerp.com>
Fri, 1 Aug 2014 13:00:18 +0000 (15:00 +0200)
28 files changed:
addons/account/res_config.py
addons/account/res_config_view.xml
addons/account_bank_statement_import/__init__.py [new file with mode: 0644]
addons/account_bank_statement_import/__openerp__.py [new file with mode: 0644]
addons/account_bank_statement_import/account_bank_statement_import.py [new file with mode: 0644]
addons/account_bank_statement_import/account_bank_statement_import_view.xml [new file with mode: 0644]
addons/account_bank_statement_import/demo/fiscalyear_period.xml [new file with mode: 0644]
addons/account_bank_statement_import/demo/partner_bank.xml [new file with mode: 0644]
addons/account_bank_statement_import_ofx/__init__.py [new file with mode: 0644]
addons/account_bank_statement_import_ofx/__openerp__.py [new file with mode: 0644]
addons/account_bank_statement_import_ofx/account_bank_statement_import_ofx.py [new file with mode: 0644]
addons/account_bank_statement_import_ofx/test_ofx_file/test_ofx.ofx [new file with mode: 0644]
addons/account_bank_statement_import_ofx/tests/__init__.py [new file with mode: 0644]
addons/account_bank_statement_import_ofx/tests/test_import_bank_statement.py [new file with mode: 0644]
addons/account_bank_statement_import_qif/__init__.py [new file with mode: 0644]
addons/account_bank_statement_import_qif/__openerp__.py [new file with mode: 0644]
addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py [new file with mode: 0644]
addons/account_bank_statement_import_qif/test_qif_file/test_qif.qif [new file with mode: 0644]
addons/account_bank_statement_import_qif/tests/__init__.py [new file with mode: 0644]
addons/account_bank_statement_import_qif/tests/test_import_bank_statement.py [new file with mode: 0644]
addons/l10n_be_coda/__openerp__.py
addons/l10n_be_coda/l10n_be_coda_view.xml
addons/l10n_be_coda/l10n_be_coda_wizard.xml [deleted file]
addons/l10n_be_coda/test_coda_file/Ontvangen_CODA.2011-01-11-18.59.15.txt [deleted file]
addons/l10n_be_coda/test_coda_file/Ontvangen_CODA.2013-01-11-18.59.15.txt [new file with mode: 0644]
addons/l10n_be_coda/tests/__init__.py [new file with mode: 0644]
addons/l10n_be_coda/tests/test_import_bank_statement.py [new file with mode: 0644]
addons/l10n_be_coda/wizard/account_coda_import.py

index 5fd111a..f729f80 100644 (file)
@@ -108,6 +108,12 @@ class account_config_settings(osv.osv_memory):
         'module_product_email_template': fields.boolean('Send products tools and information at the invoice confirmation',
             help='With this module, link your products to a template to send complete information and tools to your customer.\n'
                  'For instance when invoicing a training, the training agenda and materials will automatically be send to your customers.'),
+        'module_account_bank_statement_import_ofx': fields.boolean('Import of Bank Statements in .OFX Format',
+            help='Get your bank statements from you bank and import them in Odoo in .OFX format.\n'
+                '-that installs the module account_bank_statement_import.'),
+        'module_account_bank_statement_import_qif': fields.boolean('Import of Bank Statements in .QIF Format.',
+            help='Get your bank statements from you bank and import them in Odoo in .QIF format.\n'
+                '-that installs the module account_bank_statement_import_qif.'),
         'group_proforma_invoices': fields.boolean('Allow pro-forma invoices',
             implied_group='account.group_proforma_invoices',
             help="Allows you to put invoices in pro-forma state."),
index b33264f..5e43fd1 100644 (file)
                                 <field name="paypal_account" placeholder="e.g. sales@odoo.com" class="oe_inline"/>
                             </div>
                         </div>
+                        <label for="id" string="Bank Statements"/>
+                        <div>
+                            <div>
+                                <field name="module_account_bank_statement_import_ofx" class="oe_inline"/>
+                                <label for="module_account_bank_statement_import_ofx"/>
+                            </div>
+                            <div>
+                                <field name="module_account_bank_statement_import_qif" class="oe_inline"/>
+                                <label for="module_account_bank_statement_import_qif"/>
+                            </div>
+                        </div>
                     </group>
                     <separator name="analytic_account" string="Analytic Accounting" invisible="1"/>
                     <group name="analytic_account_sale" invisible="1">
diff --git a/addons/account_bank_statement_import/__init__.py b/addons/account_bank_statement_import/__init__.py
new file mode 100644 (file)
index 0000000..edce853
--- /dev/null
@@ -0,0 +1,5 @@
+# -*- encoding: utf-8 -*-
+
+import account_bank_statement_import
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import/__openerp__.py b/addons/account_bank_statement_import/__openerp__.py
new file mode 100644 (file)
index 0000000..6ac599c
--- /dev/null
@@ -0,0 +1,20 @@
+# -*- encoding: utf-8 -*-
+{
+    'name': 'Account Bank Statement Import',
+    'version': '1.0',
+    'author': 'OpenERP SA',
+    'depends': ['account'],
+    'demo': [],
+    'description' : """Generic Wizard to Import Bank Statements. Includes the import of files in .OFX format""",
+    'data' : [
+        'account_bank_statement_import_view.xml',
+    ],
+    'demo': [
+        'demo/fiscalyear_period.xml',
+        'demo/partner_bank.xml',
+    ],
+    'auto_install': False,
+    'installable': True,
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import/account_bank_statement_import.py b/addons/account_bank_statement_import/account_bank_statement_import.py
new file mode 100644 (file)
index 0000000..7866aeb
--- /dev/null
@@ -0,0 +1,96 @@
+# -*- coding: utf-8 -*-
+
+from openerp.osv import fields, osv
+from openerp.tools.translate import _
+
+import logging
+_logger = logging.getLogger(__name__)
+
+_IMPORT_FILE_TYPE = [('none', _('No Import Format Available'))]
+
+def add_file_type(selection_value):
+    global _IMPORT_FILE_TYPE
+    if _IMPORT_FILE_TYPE[0][0] == 'none':
+        _IMPORT_FILE_TYPE = [selection_value]
+    else:
+        _IMPORT_FILE_TYPE.append(selection_value)
+
+class account_bank_statement_import(osv.TransientModel):
+    _name = 'account.bank.statement.import'
+    _description = 'Import Bank Statement'
+
+    def _get_import_file_type(self, cr, uid, context=None):
+        return _IMPORT_FILE_TYPE
+
+    _columns = {
+        'data_file': fields.binary('Bank Statement File', required=True, help='Get you bank statements in electronic format from your bank and select them here.'),
+        'file_type': fields.selection(_get_import_file_type, 'File Type', required=True),
+        'journal_id': fields.many2one('account.journal', 'Journal', required=True, help="The journal for which the bank statements will be created"),
+    }
+
+    def _get_first_file_type(self, cr, uid, context=None):
+        return self._get_import_file_type(cr, uid, context=context)[0][0]
+
+    def _get_default_journal(self, cr, uid, context=None):
+        company_id = self.pool.get('res.company')._company_default_get(cr, uid, 'account.bank.statement', context=context)
+        journal_ids = self.pool.get('account.journal').search(cr, uid, [('type', '=', 'bank'), ('company_id', '=', company_id)], context=context)
+        return journal_ids and journal_ids[0] or False
+
+    _defaults = {
+        'file_type': _get_first_file_type,
+        'journal_id': _get_default_journal,
+    }
+
+    def _detect_partner(self, cr, uid, identifying_string, identifying_field='acc_number', context=None):
+        """Try to find a bank account and its related partner for the given 'identifying_string', looking on the field 'identifying_field'.
+
+           :param identifying_string: varchar
+           :param identifying_field: varchar corresponding to the name of a field of res.partner.bank
+           :returns: tuple(ID of the bank account found or False, ID of the partner for the bank account found or False)
+        """
+        partner_id = False
+        bank_account_id = False
+        if identifying_string:
+            ids = self.pool.get('res.partner.bank').search(cr, uid, [(identifying_field, '=', identifying_string)], context=context)
+            if ids:
+                bank_account_id = ids[0]
+                partner_id = self.pool.get('res.partner.bank').browse(cr, uid, bank_account_id, context=context).partner_id.id
+            else:
+                #create the bank account, not linked to any partner. The reconciliation will link the partner manually
+                #chosen at the bank statement final confirmation time.
+                try:
+                    type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
+                    type_id = self.pool.get('res.partner.bank.type').browse(cr, uid, type_id, context=context)
+                    bank_code = type_id.code
+                except ValueError:
+                    bank_code = 'bank'
+                acc_number = identifying_field == 'acc_number' and identifying_string or _('Undefined')
+                bank_account_vals = {
+                    'acc_number': acc_number,
+                    'state': bank_code,
+                }
+                bank_account_vals[identifying_field] = identifying_string
+                bank_account_id = self.pool.get('res.partner.bank').create(cr, uid, bank_account_vals, context=context)
+        return bank_account_id, partner_id
+
+    def import_bank_statement(self, cr, uid, bank_statement_vals=False, context=None):
+        """ Get a list of values to pass to the create() of account.bank.statement object, and returns a list of ID created using those values"""
+        statement_ids = []
+        for vals in bank_statement_vals:
+            statement_ids.append(self.pool.get('account.bank.statement').create(cr, uid, vals, context=context))
+        return statement_ids
+
+    def process_none(self, cr, uid, data_file, journal_id=False, context=None):
+        raise osv.except_osv(_('Error'), _('No available format for importing bank statement. You can install one of the file format available through the module installation.'))
+
+    def parse_file(self, cr, uid, ids, context=None):
+        """ Process the file chosen in the wizard and returns a list view of the imported bank statements"""
+        data = self.browse(cr, uid, ids[0], context=context)
+        vals = getattr(self, "process_%s" % data.file_type)(cr, uid, data.data_file, data.journal_id.id, context=context)
+        statement_ids = self.import_bank_statement(cr, uid, vals, context=context)
+        model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_bank_statement_tree')
+        action = self.pool[model].read(cr, uid, action_id, context=context)
+        action['domain'] = "[('id', 'in', [" + ', '.join(map(str, statement_ids)) + "])]"
+        return action
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import/account_bank_statement_import_view.xml b/addons/account_bank_statement_import/account_bank_statement_import_view.xml
new file mode 100644 (file)
index 0000000..b637a07
--- /dev/null
@@ -0,0 +1,46 @@
+<?xml version="1.0" ?>
+<openerp>
+    <data>
+
+        <record id="account_bank_statement_import_view" model="ir.ui.view">
+            <field name="name">Import Bank Statements</field>
+            <field name="model">account.bank.statement.import</field>
+            <field name="priority">1</field>
+            <field name="arch" type="xml">
+                <form string="Import Bank Statements" version="7.0">
+                    <group>
+                        <group>
+                            <field name="data_file"/>
+                            <field name="file_type"/>
+                            <field name="journal_id" domain="[('type', '=', 'bank')]" context="{'default_type':'bank'}"/>
+                        </group>
+                        <group>
+                            <b colspan="2"> How to import your bank statement in OpenERP.</b>
+                            <label string= "1. Go to your bank account website." colspan="2"/>
+                            <label string= "2. Download your bank statements in the right format. (.OFX, .QIF or CODA are accepted)" colspan="2"/>
+                            <label string= "3. Upload right here the bank statements file into OpenERP. Click Import." colspan="2"/>
+                        </group>
+                    </group>
+                    <footer>
+                        <button name="parse_file" string="_Import" type="object" class="oe_highlight"/>
+                        or
+                        <button string="Cancel" class="oe_link" special="cancel"/>
+                    </footer>
+                </form>
+            </field>
+        </record>
+
+        <record id="action_account_bank_statement_import" model="ir.actions.act_window">
+            <field name="name">Import Bank Statements</field>
+            <field name="type">ir.actions.act_window</field>
+            <field name="res_model">account.bank.statement.import</field>
+            <field name="view_type">form</field>
+            <field name="view_mode">form</field>
+            <field name="target">new</field>
+            <field name="view_id" ref="account_bank_statement_import_view"/>
+        </record>
+
+        <menuitem parent="account.menu_finance_bank_and_cash" id="menu_account_bank_statement_import" action="action_account_bank_statement_import" sequence="11"/>
+
+    </data>
+</openerp>
diff --git a/addons/account_bank_statement_import/demo/fiscalyear_period.xml b/addons/account_bank_statement_import/demo/fiscalyear_period.xml
new file mode 100644 (file)
index 0000000..41b4be3
--- /dev/null
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <!--
+        Fiscal year
+        -->    
+        
+        <record id="data_fiscalyear_2013" model="account.fiscalyear">
+            <field eval="'Fiscal Year X 2013'" name="name"/>
+            <field eval="'FY2013'" name="code"/>
+            <field eval="'2013-01-01'" name="date_start"/>
+            <field eval="'2013-12-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+
+        <!--
+        Fiscal Periods 2013
+        -->    
+        
+        <record id="period_1_2013" model="account.period">
+            <field eval="'01/2013'" name="code"/>
+            <field eval="'X 01/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-01-01'" name="date_start"/>
+            <field eval="'2013-01-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+
+        <record id="period_2_2013" model="account.period">
+            <field eval="'02/2013'" name="code"/>
+            <field eval="'X 02/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-02-01'" name="date_start"/>
+            <field eval="'2013-02-28'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_3_2013" model="account.period">
+            <field eval="'03/2013'" name="code"/>
+            <field eval="'X 03/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-03-01'" name="date_start"/>
+            <field eval="'2013-03-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_4_2013" model="account.period">
+            <field eval="'04/2013'" name="code"/>
+            <field eval="'X 04/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-04-01'" name="date_start"/>
+            <field eval="'2013-04-30'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_5_2013" model="account.period">
+            <field eval="'05/2013'" name="code"/>
+            <field eval="'X 05/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-05-01'" name="date_start"/>
+            <field eval="'2013-05-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_6_2013" model="account.period">
+            <field eval="'06/2013'" name="code"/>
+            <field eval="'X 06/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-06-01'" name="date_start"/>
+            <field eval="'2013-06-30'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_7_2013" model="account.period">
+            <field eval="'07/2013'" name="code"/>
+            <field eval="'X 07/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-07-01'" name="date_start"/>
+            <field eval="'2013-07-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_8_2013" model="account.period">
+            <field eval="'08/2013'" name="code"/>
+            <field eval="'X 08/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-08-01'" name="date_start"/>
+            <field eval="'2013-08-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_9_2013" model="account.period">
+            <field eval="'09/2013'" name="code"/>
+            <field eval="'X 09/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-09-01'" name="date_start"/>
+            <field eval="'2013-09-30'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_10_2013" model="account.period">
+            <field eval="'10/2013'" name="code"/>
+            <field eval="'X 10/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-10-01'" name="date_start"/>
+            <field eval="'2013-10-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_11_2013" model="account.period">
+            <field eval="'11/2013'" name="code"/>
+            <field eval="'X 11/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-11-01'" name="date_start"/>
+            <field eval="'2013-11-30'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+        <record id="period_12_2013" model="account.period">
+            <field eval="'12/2013'" name="code"/>
+            <field eval="'X 12/2013'" name="name"/>
+            <field name="fiscalyear_id" ref="data_fiscalyear_2013"/>
+            <field eval="'2013-12-01'" name="date_start"/>
+            <field eval="'2013-12-31'" name="date_stop"/>
+            <field name="company_id" ref="base.main_company"/>
+        </record>
+    </data>
+</openerp>
diff --git a/addons/account_bank_statement_import/demo/partner_bank.xml b/addons/account_bank_statement_import/demo/partner_bank.xml
new file mode 100644 (file)
index 0000000..47e8fa7
--- /dev/null
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<openerp>
+    <data>
+
+        <record id="ofx_partner_bank_1" model="res.partner.bank">
+            <field name="owner_name">Agrolait</field>
+            <field name="acc_number">00987654321</field>
+            <field name="partner_id" ref="base.res_partner_2"></field>
+            <field name="state">bank</field>
+            <field name="bank" ref="base.res_bank_1"/>
+        </record>
+
+        <record id="ofx_partner_bank_2" model="res.partner.bank">
+            <field name="owner_name">China Export</field>
+            <field name="acc_number">00987654322</field>
+            <field name="partner_id" ref="base.res_partner_3"></field>
+            <field name="state">bank</field>
+            <field name="bank" ref="base.res_bank_1"/>
+        </record>
+
+        <record id="qif_partner_bank_1" model="res.partner.bank">
+            <field name="owner_name">Delta PC</field>
+            <field name="acc_number">10987654320</field>
+            <field name="partner_id" ref="base.res_partner_4"></field>
+            <field name="state">bank</field>
+            <field name="bank" ref="base.res_bank_1"/>
+        </record>
+
+        <record id="qif_partner_bank_2" model="res.partner.bank">
+            <field name="owner_name">Epic Technologies</field>
+            <field name="acc_number">10987654322</field>
+            <field name="partner_id" ref="base.res_partner_5"></field>
+            <field name="state">bank</field>
+            <field name="bank" ref="base.res_bank_1"/>
+        </record>
+
+    </data>
+</openerp>
diff --git a/addons/account_bank_statement_import_ofx/__init__.py b/addons/account_bank_statement_import_ofx/__init__.py
new file mode 100644 (file)
index 0000000..fe838c2
--- /dev/null
@@ -0,0 +1,5 @@
+# -*- encoding: utf-8 -*-
+
+import account_bank_statement_import_ofx
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import_ofx/__openerp__.py b/addons/account_bank_statement_import_ofx/__openerp__.py
new file mode 100644 (file)
index 0000000..baf0c66
--- /dev/null
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+{
+    'name': 'Import OFX Bank Statement',
+    'version': '1.0',
+    'author': 'OpenERP SA',
+    'depends': ['account_bank_statement_import'],
+    'demo': [],
+    'description' : """
+Module to import OFX bank statements.
+======================================
+
+This module allows you to import the machine readable OFX Files in Odoo: they are parsed and stored in human readable format in 
+Accounting \ Bank and Cash \ Bank Statements.
+
+Bank Statements may be generated containing a subset of the OFX information (only those transaction lines that are required for the 
+creation of the Financial Accounting records). 
+    
+    """,
+    'data' : [],
+    'demo': [],
+    'auto_install': False,
+    'installable': True,
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import_ofx/account_bank_statement_import_ofx.py b/addons/account_bank_statement_import_ofx/account_bank_statement_import_ofx.py
new file mode 100644 (file)
index 0000000..13966c0
--- /dev/null
@@ -0,0 +1,74 @@
+# -*- coding: utf-8 -*-
+
+import logging
+import base64
+import os
+
+from openerp.osv import osv
+from openerp.tools.translate import _
+
+_logger = logging.getLogger(__name__)
+
+from openerp.addons.account_bank_statement_import import account_bank_statement_import as ibs
+ibs.add_file_type(('ofx', 'OFX'))
+
+try:
+    from ofxparse import OfxParser as ofxparser
+except ImportError:
+    _logger.warning("OFX parser unavailable because the `ofxparse` Python library cannot be found."
+                    "It can be downloaded and installed from `https://pypi.python.org/pypi/ofxparse`.")
+    ofxparser = None
+
+class account_bank_statement_import(osv.TransientModel):
+    _inherit = 'account.bank.statement.import'
+
+    def process_ofx(self, cr, uid, data_file, journal_id=False, context=None):
+        """ Import a file in the .OFX format"""
+        if ofxparser is None:
+            raise osv.except_osv(_("Error"), _("OFX parser unavailable because the `ofxparse` Python library cannot be found."
+                    "It can be downloaded and installed from `https://pypi.python.org/pypi/ofxparse`."))
+        try:
+            tempfile = open("temp.ofx", "w+")
+            tempfile.write(base64.decodestring(data_file))
+            tempfile.read()
+            pathname = os.path.dirname('temp.ofx')
+            path = os.path.join(os.path.abspath(pathname), 'temp.ofx')
+            ofx = ofxparser.parse(file(path))
+        except:
+            raise osv.except_osv(_('Import Error!'), _('Please check OFX file format is proper or not.'))
+        line_ids = []
+        total_amt = 0.00
+        try:
+            for transaction in ofx.account.statement.transactions:
+                bank_account_id, partner_id = self._detect_partner(cr, uid, transaction.payee, identifying_field='owner_name', context=context)
+                vals_line = {
+                    'date': transaction.date,
+                    'name': transaction.payee + ': ' + transaction.memo,
+                    'ref': transaction.id,
+                    'amount': transaction.amount,
+                    'partner_id': partner_id,
+                    'bank_account_id': bank_account_id,
+                }
+                total_amt += float(transaction.amount)
+                line_ids.append((0, 0, vals_line))
+        except Exception, e:
+            raise osv.except_osv(_('Error!'), _("Following problem has been occurred while importing your file, Please verify the file is proper or not.\n\n %s" % e.message))
+        st_start_date = ofx.account.statement.start_date or False
+        st_end_date = ofx.account.statement.end_date or False
+        period_obj = self.pool.get('account.period')
+        if st_end_date:
+            period_ids = period_obj.find(cr, uid, st_end_date, context=context)
+        else:
+            period_ids = period_obj.find(cr, uid, st_start_date, context=context)
+        vals_bank_statement = {
+            'name': ofx.account.routing_number,
+            'balance_start': ofx.account.statement.balance,
+            'balance_end_real': float(ofx.account.statement.balance) + total_amt,
+            'period_id': period_ids and period_ids[0] or False,
+            'journal_id': journal_id
+        }
+        vals_bank_statement.update({'line_ids': line_ids})
+        os.remove(path)
+        return [vals_bank_statement]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import_ofx/test_ofx_file/test_ofx.ofx b/addons/account_bank_statement_import_ofx/test_ofx_file/test_ofx.ofx
new file mode 100644 (file)
index 0000000..37df4d0
--- /dev/null
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="ASCII"?>
+<?OFX OFXHEADER="200" VERSION="211" SECURITY="NONE" OLDFILEUID="NONE" NEWFILEUID="NONE"?>
+<OFX>
+  <SIGNONMSGSRSV1>
+    <SONRS>
+      <STATUS>
+        <CODE>0</CODE>
+        <SEVERITY>INFO</SEVERITY>
+      </STATUS>
+      <DTSERVER>20130831165153.000[-8:PST]</DTSERVER>
+      <LANGUAGE>ENG</LANGUAGE>
+    </SONRS>
+  </SIGNONMSGSRSV1>
+  <BANKMSGSRSV1>
+    <STMTTRNRS>
+      <TRNUID>0</TRNUID>
+      <STATUS>
+        <CODE>0</CODE>
+        <SEVERITY>INFO</SEVERITY>
+      </STATUS>
+      <STMTRS>
+        <CURDEF>USD</CURDEF>
+        <BANKACCTFROM>
+          <BANKID>000000123</BANKID>
+          <ACCTID>123456</ACCTID>
+          <ACCTTYPE>CHECKING</ACCTTYPE>
+        </BANKACCTFROM>
+        <BANKTRANLIST>
+          <DTSTART>20130801</DTSTART>
+          <DTEND>20130831165153.000[-8:PST]</DTEND>
+          <STMTTRN>
+            <TRNTYPE>POS</TRNTYPE>
+            <DTPOSTED>20130824080000</DTPOSTED>
+            <TRNAMT>-80</TRNAMT>
+            <FITID>219378</FITID>
+            <NAME>Agrolait</NAME>
+          </STMTTRN>
+        </BANKTRANLIST>
+        <BANKTRANLIST>
+          <DTSTART>20130801</DTSTART>
+          <DTEND>20130831165153.000[-8:PST]</DTEND>
+          <STMTTRN>
+            <TRNTYPE>POS</TRNTYPE>
+            <DTPOSTED>20130824080000</DTPOSTED>
+            <TRNAMT>-90</TRNAMT>
+            <FITID>219379</FITID>
+            <NAME>China Export</NAME>
+          </STMTTRN>
+        </BANKTRANLIST>
+        <BANKTRANLIST>
+          <DTSTART>20130801</DTSTART>
+          <DTEND>20130831165153.000[-8:PST]</DTEND>
+          <STMTTRN>
+            <TRNTYPE>POS</TRNTYPE>
+            <DTPOSTED>20130824080000</DTPOSTED>
+            <TRNAMT>-100</TRNAMT>
+            <FITID>219380</FITID>
+            <NAME>Axelor Scuba</NAME>
+          </STMTTRN>
+        </BANKTRANLIST>
+        <BANKTRANLIST>
+          <DTSTART>20130801</DTSTART>
+          <DTEND>20130831165153.000[-8:PST]</DTEND>
+          <STMTTRN>
+            <TRNTYPE>POS</TRNTYPE>
+            <DTPOSTED>20130824080000</DTPOSTED>
+            <TRNAMT>-90</TRNAMT>
+            <FITID>219381</FITID>
+            <NAME>China Scuba</NAME>
+          </STMTTRN>
+        </BANKTRANLIST>
+        <LEDGERBAL>
+          <BALAMT>2156.56</BALAMT>
+          <DTASOF>20130831165153</DTASOF>
+        </LEDGERBAL>
+      </STMTRS>
+    </STMTTRNRS>
+  </BANKMSGSRSV1>
+  <CREDITCARDMSGSRSV1>
+    <CCSTMTTRNRS>
+      <TRNUID>0</TRNUID>
+      <STATUS>
+        <CODE>0</CODE>
+        <SEVERITY>INFO</SEVERITY>
+      </STATUS>
+      <CCSTMTRS>
+        <CURDEF>USD</CURDEF>
+        <CCACCTFROM>
+          <ACCTID>123412341234</ACCTID>
+        </CCACCTFROM>
+        <BANKTRANLIST>
+        </BANKTRANLIST>
+        <LEDGERBAL>
+          <BALAMT>-562.00</BALAMT>
+          <DTASOF>20130831165153</DTASOF>
+        </LEDGERBAL>
+      </CCSTMTRS>
+    </CCSTMTTRNRS>
+  </CREDITCARDMSGSRSV1>
+</OFX>
diff --git a/addons/account_bank_statement_import_ofx/tests/__init__.py b/addons/account_bank_statement_import_ofx/tests/__init__.py
new file mode 100644 (file)
index 0000000..8a5a8e9
--- /dev/null
@@ -0,0 +1,5 @@
+from . import test_import_bank_statement
+
+checks = [
+        test_import_bank_statement
+]
diff --git a/addons/account_bank_statement_import_ofx/tests/test_import_bank_statement.py b/addons/account_bank_statement_import_ofx/tests/test_import_bank_statement.py
new file mode 100644 (file)
index 0000000..967d647
--- /dev/null
@@ -0,0 +1,30 @@
+from openerp.tests.common import TransactionCase
+from openerp.modules.module import get_module_resource
+
+class TestOfxFile(TransactionCase):
+    """Tests for import bank statement ofx file format (account.bank.statement.import)
+    """
+
+    def setUp(self):
+        super(TestOfxFile, self).setUp()
+        self.statement_import_model = self.registry('account.bank.statement.import')
+        self.bank_statement_model = self.registry('account.bank.statement')
+
+    def test_ofx_file_import(self):
+        try:
+            from ofxparse import OfxParser as ofxparser
+        except ImportError:
+            #the Python library isn't installed on the server, the OFX import is unavailable and the test cannot be run
+            return True
+        cr, uid = self.cr, self.uid
+        ofx_file_path = get_module_resource('account_bank_statement_import_ofx', 'test_ofx_file', 'test_ofx.ofx')
+        ofx_file = open(ofx_file_path, 'rb').read().encode('base64')
+        bank_statement_id = self.statement_import_model.create(cr, uid, dict(
+                            file_type='ofx',
+                            data_file=ofx_file,
+                            ))
+        self.statement_import_model.parse_file(cr, uid, [bank_statement_id])
+        statement_id = self.bank_statement_model.search(cr, uid, [('name', '=', '000000123')])[0]
+        bank_st_record = self.bank_statement_model.browse(cr, uid, statement_id)
+        self.assertEquals(bank_st_record.balance_start, 2156.56)
+        self.assertEquals(bank_st_record.balance_end_real, 1796.56)
diff --git a/addons/account_bank_statement_import_qif/__init__.py b/addons/account_bank_statement_import_qif/__init__.py
new file mode 100644 (file)
index 0000000..befbd0e
--- /dev/null
@@ -0,0 +1,5 @@
+# -*- coding: utf-8 -*-
+
+import account_bank_statement_import_qif
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import_qif/__openerp__.py b/addons/account_bank_statement_import_qif/__openerp__.py
new file mode 100644 (file)
index 0000000..dad736a
--- /dev/null
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+
+{
+    'name': 'Import QIF Bank Statement',
+    'version': '1.0',
+    'author': 'OpenERP SA',
+    'description': '''
+Module to import QIF bank statements.
+======================================
+
+This module allows you to import the machine readable QIF Files in Odoo: they are parsed and stored in human readable format in 
+Accounting \ Bank and Cash \ Bank Statements.
+
+Bank Statements may be generated containing a subset of the QIF information (only those transaction lines that are required for the 
+creation of the Financial Accounting records). 
+''',
+    'images' : [],
+    'depends': ['account_bank_statement_import'],
+    'demo': [],
+    'data': [],
+    'auto_install': False,
+    'installable': True,
+}
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py b/addons/account_bank_statement_import_qif/account_bank_statement_import_qif.py
new file mode 100644 (file)
index 0000000..a253cb6
--- /dev/null
@@ -0,0 +1,75 @@
+# -*- coding: utf-8 -*-
+
+import dateutil.parser
+import base64
+from tempfile import TemporaryFile
+
+from openerp.tools.translate import _
+from openerp.osv import osv
+
+from openerp.addons.account_bank_statement_import import account_bank_statement_import as ibs
+
+ibs.add_file_type(('qif', 'QIF'))
+
+class account_bank_statement_import(osv.TransientModel):
+    _inherit = "account.bank.statement.import"
+
+    def process_qif(self, cr, uid, data_file, journal_id=False, context=None):
+        """ Import a file in the .QIF format"""
+        try:
+            fileobj = TemporaryFile('wb+')
+            fileobj.write(base64.b64decode(data_file))
+            fileobj.seek(0)
+            file_data = ""
+            for line in fileobj.readlines():
+                file_data += line
+            fileobj.close()
+            if '\r' in file_data:
+                data_list = file_data.split('\r')
+            else:
+                data_list = file_data.split('\n')
+            header = data_list[0].strip()
+            header = header.split(":")[1]
+        except:
+            raise osv.except_osv(_('Import Error!'), _('Please check QIF file format is proper or not.'))
+        line_ids = []
+        vals_line = {}
+        total = 0
+        if header == "Bank":
+            vals_bank_statement = {}
+            for line in data_list:
+                line = line.strip()
+                if not line:
+                    continue
+                if line[0] == 'D':  # date of transaction
+                    vals_line['date'] = dateutil.parser.parse(line[1:], fuzzy=True).date()
+                    if vals_line.get('date') and not vals_bank_statement.get('period_id'):
+                        period_ids = self.pool.get('account.period').find(cr, uid, vals_line['date'], context=context)
+                        vals_bank_statement.update({'period_id': period_ids and period_ids[0] or False})
+                elif line[0] == 'T':  # Total amount
+                    total += float(line[1:].replace(',', ''))
+                    vals_line['amount'] = float(line[1:].replace(',', ''))
+                elif line[0] == 'N':  # Check number
+                    vals_line['ref'] = line[1:]
+                elif line[0] == 'P':  # Payee
+                    bank_account_id, partner_id = self._detect_partner(cr, uid, line[1:], identifying_field='owner_name', context=context)
+                    vals_line['partner_id'] = partner_id
+                    vals_line['bank_account_id'] = bank_account_id
+                    vals_line['name'] = 'name' in vals_line and line[1:] + ': ' + vals_line['name'] or line[1:]
+                elif line[0] == 'M':  # Memo
+                    vals_line['name'] = 'name' in vals_line and vals_line['name'] + ': ' + line[1:] or line[1:]
+                elif line[0] == '^':  # end of item
+                    line_ids.append((0, 0, vals_line))
+                    vals_line = {}
+                elif line[0] == '\n':
+                    line_ids = []
+                else:
+                    pass
+        else:
+            raise osv.except_osv(_('Error!'), _('Cannot support this Format !Type:%s.') % (header,))
+        vals_bank_statement.update({'balance_end_real': total,
+                                    'line_ids': line_ids,
+                                    'journal_id': journal_id})
+        return [vals_bank_statement]
+
+# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/addons/account_bank_statement_import_qif/test_qif_file/test_qif.qif b/addons/account_bank_statement_import_qif/test_qif_file/test_qif.qif
new file mode 100644 (file)
index 0000000..5388e6d
--- /dev/null
@@ -0,0 +1,21 @@
+!Type:Bank
+D8/12/13
+T-1,000.00
+PDelta PC
+^
+D8/15/13
+T-75.46
+PWalts Drugs
+^
+D3/3/13
+T-379.00
+PEpic Technologies
+^
+D3/4/13
+T-20.28
+PYOUR LOCAL SUPERMARKET
+^
+D3/3/13
+T-421.35
+PSPRINGFIELD WATER UTILITY
+^
diff --git a/addons/account_bank_statement_import_qif/tests/__init__.py b/addons/account_bank_statement_import_qif/tests/__init__.py
new file mode 100644 (file)
index 0000000..05b23c4
--- /dev/null
@@ -0,0 +1,5 @@
+from . import test_import_bank_statement
+checks = [
+    test_import_bank_statement
+]
+
diff --git a/addons/account_bank_statement_import_qif/tests/test_import_bank_statement.py b/addons/account_bank_statement_import_qif/tests/test_import_bank_statement.py
new file mode 100644 (file)
index 0000000..0f9ef4d
--- /dev/null
@@ -0,0 +1,27 @@
+from openerp.tests.common import TransactionCase
+from openerp.modules.module import get_module_resource
+
+class TestQifFile(TransactionCase):
+    """Tests for import bank statement qif file format (account.bank.statement.import)
+    """
+
+    def setUp(self):
+        super(TestQifFile, self).setUp()
+        self.statement_import_model = self.registry('account.bank.statement.import')
+        self.bank_statement_model = self.registry('account.bank.statement')
+        self.bank_statement_line_model = self.registry('account.bank.statement.line')
+
+    def test_qif_file_import(self):
+        from openerp.tools import float_compare
+        cr, uid = self.cr, self.uid
+        qif_file_path = get_module_resource('account_bank_statement_import_qif', 'test_qif_file', 'test_qif.qif')
+        qif_file = open(qif_file_path, 'rb').read().encode('base64')
+        bank_statement_id = self.statement_import_model.create(cr, uid, dict(
+                            file_type='qif',
+                            data_file=qif_file,
+                            ))
+        self.statement_import_model.parse_file(cr, uid, [bank_statement_id])
+        line_id = self.bank_statement_line_model.search(cr, uid, [('name', '=', 'YOUR LOCAL SUPERMARKET')])[0]
+        statement_id = self.bank_statement_line_model.browse(cr, uid, line_id).statement_id.id
+        bank_st_record = self.bank_statement_model.browse(cr, uid, statement_id)
+        assert float_compare(bank_st_record.balance_end_real, -1896.09, 2) == 0
index 6ecdb04..c45e4e4 100644 (file)
@@ -72,10 +72,9 @@ V2.2 specifications.
 If required, you can manually adjust the descriptions via the CODA configuration menu.
 ''',
     'images': ['images/coda_logs.jpeg', 'images/import_coda_logs.jpeg'],
-    'depends': ['account_voucher', 'base_iban', 'l10n_be_invoice_bba'],
+    'depends': ['account_voucher', 'base_iban', 'l10n_be_invoice_bba', 'account_bank_statement_import'],
     'demo': ['l10n_be_coda_demo.xml'],
     'data': [
-        'l10n_be_coda_wizard.xml',
         'l10n_be_coda_view.xml',
     ],
     'auto_install': False,
index dc147ae..6983bc1 100644 (file)
@@ -85,6 +85,5 @@
                </record>
 
         <menuitem name="Bank Statement Lines" parent="account.menu_finance_bank_and_cash" id="menu_account_bank_statement_line_coda" action="action_account_bank_statement_line_coda" sequence="8" groups="base.group_no_one"/>
-       <menuitem name="Import CODA File" parent="account.menu_finance_bank_and_cash" id="menu_account_coda_import" action="action_account_coda_import" sequence="10"/>
        </data> 
 </openerp>
\ No newline at end of file
diff --git a/addons/l10n_be_coda/l10n_be_coda_wizard.xml b/addons/l10n_be_coda/l10n_be_coda_wizard.xml
deleted file mode 100644 (file)
index 627de37..0000000
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" ?>
-<openerp>
-    <data>
-
-    <record id="account_coda_import_view" model="ir.ui.view">
-      <field name="name">Import CODA File</field>
-      <field name="model">account.coda.import</field>
-      <field name="priority">1</field>
-      <field name="arch" type="xml">
-        <form string="Import CODA File">
-            <group col="2">
-                <field name="coda_data" filename="coda_fname"/>
-            </group>
-            <footer>
-                <button name="coda_parsing" string="_Import" type="object" class="oe_highlight"/>
-                or
-                <button string="Cancel" class="oe_link" special="cancel"/>
-            </footer>
-        </form>
-      </field>
-    </record>
-
-    <record id="action_account_coda_import" model="ir.actions.act_window">
-      <field name="name">Import CODA File</field>
-      <field name="type">ir.actions.act_window</field>
-      <field name="res_model">account.coda.import</field>
-      <field name="view_type">form</field>
-      <field name="view_mode">form</field>
-      <field name="target">new</field>
-      <field name="view_id" ref="account_coda_import_view"/>
-    </record>
-    
-  </data> 
-</openerp>
diff --git a/addons/l10n_be_coda/test_coda_file/Ontvangen_CODA.2011-01-11-18.59.15.txt b/addons/l10n_be_coda/test_coda_file/Ontvangen_CODA.2011-01-11-18.59.15.txt
deleted file mode 100644 (file)
index d0add85..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-0000011011172505        00178299  DE MEYER LUC              KREDBEBB   00820512013 00000                                       2\r
-12135BE33737018595246                  EUR0000000011812700270710NOVIAT NV                 KBC-Business Comfortrekening       003\r
-2100010000OL44483FW SCTOFBIONLO1000000000435000110111001010000MEDEDELING                                           11011113501 0\r
-2200010000                                                                                        GKCCBEBB                   1 0\r
-2300010000BE41063012345610                     PARTNER 1                                                                     0 1\r
-3100010001OL44483FW SCTOFBIONLO001010001001PARTNER 1                                                                         0 0\r
-2100020000OL4414AC8BOVSOVSOVERS0000000003044450110111001500001101240283842818                                      11011113501 0\r
-2200020000                                                                                        BBRUBEBB                   1 0\r
-2300020000BE61310126985517                     PARTNER 2                                                                     0 1\r
-3100020001OL4414AC8BOVSOVSOVERS001500001001PARTNER 2                                                                         1 0\r
-3200020001MOLENSTRAAT 60                     9340    LEDE                                                                    0 0\r
-2100030000AFECA0CVA IKLINNINNIG1000000000479040110111313410000              KBC-INVESTERINGSKREDIET 737-6543210-21 11011113510 0\r
-2100030001AFECA0CVA IKLINNINNIG1000000000419920110111813410660                                                     11011113500 0\r
-2100030002AFECA0CVA IKLINNINNIG1000000000059120110111813410020                                                     11011113510 0\r
-2100040000AFECA0CVA IKLINNINNIG1000000000479040110111313410000              KBC-INVESTERINGSKREDIET 737-6543210-21 11011113510 0\r
-2100040001AFECA0CVA IKLINNINNIG1000000000419920110111813410660                                                     11011113500 0\r
-2100040002AFECA0CVA IKLINNINNIG1000000000059120110111813410020                                                     11011113510 0\r
-2100050000AOGM00160BSCTOBOGOVER0000000000063740110111001500000TERUGGAVE 37232481 8400083296 .                      11011113501 0\r
-2200050000                                                     362/363                            KREDBEBB                   1 0\r
-2300050000BE43730004200601                     KBC VERZEKERINGEN NV                                                          0 1\r
-3100050001AOGM00160BSCTOBOGOVER001500001001KBC VERZEKERINGEN NV                                                              1 0\r
-3200050001VAN OVERSTRAETENPLEIN 2            3000    LEUVEN                                                                  0 0\r
-8135BE44734024486445                  EUR0000000013527810110111                                                                0\r
-9               000022000000001393080000000003108190                                                                           2\r
diff --git a/addons/l10n_be_coda/test_coda_file/Ontvangen_CODA.2013-01-11-18.59.15.txt b/addons/l10n_be_coda/test_coda_file/Ontvangen_CODA.2013-01-11-18.59.15.txt
new file mode 100644 (file)
index 0000000..d0add85
--- /dev/null
@@ -0,0 +1,24 @@
+0000011011172505        00178299  DE MEYER LUC              KREDBEBB   00820512013 00000                                       2\r
+12135BE33737018595246                  EUR0000000011812700270710NOVIAT NV                 KBC-Business Comfortrekening       003\r
+2100010000OL44483FW SCTOFBIONLO1000000000435000110111001010000MEDEDELING                                           11011113501 0\r
+2200010000                                                                                        GKCCBEBB                   1 0\r
+2300010000BE41063012345610                     PARTNER 1                                                                     0 1\r
+3100010001OL44483FW SCTOFBIONLO001010001001PARTNER 1                                                                         0 0\r
+2100020000OL4414AC8BOVSOVSOVERS0000000003044450110111001500001101240283842818                                      11011113501 0\r
+2200020000                                                                                        BBRUBEBB                   1 0\r
+2300020000BE61310126985517                     PARTNER 2                                                                     0 1\r
+3100020001OL4414AC8BOVSOVSOVERS001500001001PARTNER 2                                                                         1 0\r
+3200020001MOLENSTRAAT 60                     9340    LEDE                                                                    0 0\r
+2100030000AFECA0CVA IKLINNINNIG1000000000479040110111313410000              KBC-INVESTERINGSKREDIET 737-6543210-21 11011113510 0\r
+2100030001AFECA0CVA IKLINNINNIG1000000000419920110111813410660                                                     11011113500 0\r
+2100030002AFECA0CVA IKLINNINNIG1000000000059120110111813410020                                                     11011113510 0\r
+2100040000AFECA0CVA IKLINNINNIG1000000000479040110111313410000              KBC-INVESTERINGSKREDIET 737-6543210-21 11011113510 0\r
+2100040001AFECA0CVA IKLINNINNIG1000000000419920110111813410660                                                     11011113500 0\r
+2100040002AFECA0CVA IKLINNINNIG1000000000059120110111813410020                                                     11011113510 0\r
+2100050000AOGM00160BSCTOBOGOVER0000000000063740110111001500000TERUGGAVE 37232481 8400083296 .                      11011113501 0\r
+2200050000                                                     362/363                            KREDBEBB                   1 0\r
+2300050000BE43730004200601                     KBC VERZEKERINGEN NV                                                          0 1\r
+3100050001AOGM00160BSCTOBOGOVER001500001001KBC VERZEKERINGEN NV                                                              1 0\r
+3200050001VAN OVERSTRAETENPLEIN 2            3000    LEUVEN                                                                  0 0\r
+8135BE44734024486445                  EUR0000000013527810110111                                                                0\r
+9               000022000000001393080000000003108190                                                                           2\r
diff --git a/addons/l10n_be_coda/tests/__init__.py b/addons/l10n_be_coda/tests/__init__.py
new file mode 100644 (file)
index 0000000..05b23c4
--- /dev/null
@@ -0,0 +1,5 @@
+from . import test_import_bank_statement
+checks = [
+    test_import_bank_statement
+]
+
diff --git a/addons/l10n_be_coda/tests/test_import_bank_statement.py b/addons/l10n_be_coda/tests/test_import_bank_statement.py
new file mode 100644 (file)
index 0000000..759b6d3
--- /dev/null
@@ -0,0 +1,39 @@
+from openerp.tests.common import TransactionCase
+from openerp.modules.module import get_module_resource
+
+class TestCodaFile(TransactionCase):
+    """Tests for import bank statement coda file format (account.bank.statement.import)
+    """
+
+    def setUp(self):
+        super(TestCodaFile, self).setUp()
+        self.statement_import_model = self.registry('account.bank.statement.import')
+        self.bank_statement_model = self.registry('account.bank.statement')
+
+    def test_coda_file_import(self):
+        cr, uid = self.cr, self.uid
+        bank_temp_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'account', 'conf_bnk')
+        partner_id_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'main_partner')
+        company_id_ref = self.registry('ir.model.data').get_object_reference(cr, uid, 'base', 'main_company')
+        self.bank_temp_id = bank_temp_ref and bank_temp_ref[1] or False
+        self.partner_id = partner_id_ref and partner_id_ref[1] or False
+        self.company_id = company_id_ref and company_id_ref[1] or False
+        coda_file_path = get_module_resource('l10n_be_coda', 'test_coda_file', 'Ontvangen_CODA.2013-01-11-18.59.15.txt')
+        coda_file = open(coda_file_path, 'rb').read().encode('base64')
+        bank_account_id = self.registry('res.partner.bank').create(cr, uid, dict(
+                        state = 'bank',
+                        acc_number = 'BE33737018595246',
+                        bank_name = 'Reserve',
+                        partner_id = self.partner_id,
+                        company_id = self.company_id
+                        ))
+        bank_statement_id = self.statement_import_model.create(cr, uid, dict(
+                        file_type = 'coda',
+                        data_file = coda_file,
+                         ))
+        self.statement_import_model.parse_file(cr, uid, [bank_statement_id])
+        statement_id = self.bank_statement_model.search(cr, uid, [('name', '=', '135')])[0]
+        bank_st_record = self.bank_statement_model.browse(cr, uid, statement_id)
+        self.assertEquals(bank_st_record.balance_start, 11812.70)
+        self.assertEquals(bank_st_record.balance_end_real, 13527.81)
+
index 2670a44..5790e50 100644 (file)
@@ -22,7 +22,7 @@
 import base64
 import time
 
-from openerp.osv import fields, osv
+from openerp.osv import osv
 from openerp.tools.translate import _
 from openerp import tools
 
@@ -30,33 +30,16 @@ import logging
 
 _logger = logging.getLogger(__name__)
 
-class account_coda_import(osv.osv_memory):
-    _name = 'account.coda.import'
-    _description = 'Import CODA File'
-    _columns = {
-        'coda_data': fields.binary('CODA File', required=True),
-        'coda_fname': fields.char('CODA Filename', required=True),
-        'note': fields.text('Log'),
-    }
+from openerp.addons.account_bank_statement_import import account_bank_statement_import as coda_ibs
 
-    _defaults = {
-        'coda_fname': lambda *a: '',
-    }
+coda_ibs.add_file_type(('coda', 'CODA'))
 
-    def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None):
+class account_bank_statement_import(osv.TransientModel):
+    _inherit = "account.bank.statement.import"
+
+    def process_coda(self, cr, uid, codafile=None, journal_id=False, context=None):
         if context is None:
             context = {}
-        if batch:
-            codafile = str(codafile)
-            codafilename = codafilename
-        else:
-            data = self.browse(cr, uid, ids)[0]
-            try:
-                codafile = data.coda_data
-                codafilename = data.coda_fname
-            except:
-                raise osv.except_osv(_('Error'), _('Wizard in incorrect state. Please hit the Cancel button'))
-                return {}
         recordlist = unicode(base64.decodestring(codafile), 'windows-1252', 'strict').split('\n')
         statements = []
         for line in recordlist:
@@ -119,7 +102,7 @@ class account_coda_import(osv.osv_memory):
                     raise osv.except_osv(_('Error') + ' R1004', _("No matching Bank Account (with Account Journal) found.\n\nPlease set-up a Bank Account with as Account Number '%s' and as Currency '%s' and an Account Journal.") % (statement['acc_number'], statement['currency']))
                 statement['description'] = rmspaces(line[90:125])
                 statement['balance_start'] = float(rmspaces(line[43:58])) / 1000
-                if line[42] == '1':    #1 = Debit, the starting balance is negative
+                if line[42] == '1':  # 1 = Debit, the starting balance is negative
                     statement['balance_start'] = - statement['balance_start']
                 statement['balance_start_date'] = time.strftime(tools.DEFAULT_SERVER_DATE_FORMAT, time.strptime(rmspaces(line[58:64]), '%d%m%y'))
                 statement['accountHolder'] = rmspaces(line[64:90])
@@ -241,6 +224,7 @@ class account_coda_import(osv.osv_memory):
                     statement['balance_end_real'] = statement['balance_start'] + statement['balancePlus'] - statement['balanceMin']
         for i, statement in enumerate(statements):
             statement['coda_note'] = ''
+            statement_line = []
             balance_start_check_date = (len(statement['lines']) > 0 and statement['lines'][0]['entryDate']) or statement['date']
             cr.execute('SELECT balance_end_real \
                 FROM account_bank_statement \
@@ -248,7 +232,7 @@ class account_coda_import(osv.osv_memory):
                 ORDER BY date DESC,id DESC LIMIT 1', (statement['journal_id'].id, balance_start_check_date))
             res = cr.fetchone()
             balance_start_check = res and res[0]
-            if balance_start_check == None:
+            if balance_start_check is None:
                 if statement['journal_id'].default_debit_account_id and (statement['journal_id'].default_credit_account_id == statement['journal_id'].default_debit_account_id):
                     balance_start_check = statement['journal_id'].default_debit_account_id.balance
                 else:
@@ -257,7 +241,7 @@ class account_coda_import(osv.osv_memory):
                 statement['coda_note'] = _("The CODA Statement %s Starting Balance (%.2f) does not correspond with the previous Closing Balance (%.2f) in journal %s!") % (statement['description'] + ' #' + statement['paperSeqNumber'], statement['balance_start'], balance_start_check, statement['journal_id'].name)
             if not(statement.get('period_id')):
                 raise osv.except_osv(_('Error') + ' R3006', _(' No transactions or no period in coda file !'))
-            data = {
+            statement_data = {
                 'name': statement['paperSeqNumber'],
                 'date': statement['date'],
                 'journal_id': statement['journal_id'].id,
@@ -265,7 +249,6 @@ class account_coda_import(osv.osv_memory):
                 'balance_start': statement['balance_start'],
                 'balance_end_real': statement['balance_end_real'],
             }
-            statement['id'] = self.pool.get('account.bank.statement').create(cr, uid, data, context=context)
             for line in statement['lines']:
                 if line['type'] == 'information':
                     statement['coda_note'] = "\n".join([statement['coda_note'], line['type'].title() + ' with Ref. ' + str(line['ref']), 'Date: ' + str(line['entryDate']), 'Communication: ' + line['communication'], ''])
@@ -291,55 +274,30 @@ class account_coda_import(osv.osv_memory):
                     if 'counterpartyAddress' in line and line['counterpartyAddress'] != '':
                         note.append(_('Counter Party Address') + ': ' + line['counterpartyAddress'])
                     line['name'] = "\n".join(filter(None, [line['counterpartyName'], line['communication']]))
-                    partner_id = None
                     structured_com = ""
-                    bank_account_id = False
                     if line['communication_struct'] and 'communication_type' in line and line['communication_type'] == '101':
                         structured_com = line['communication']
+                    bank_account_id = False
+                    partner_id = False
                     if 'counterpartyNumber' in line and line['counterpartyNumber']:
-                        ids = self.pool.get('res.partner.bank').search(cr, uid, [('acc_number', '=', str(line['counterpartyNumber']))])
-                        if ids:
-                            bank_account_id = ids[0]
-                            partner_id = self.pool.get('res.partner.bank').browse(cr, uid, bank_account_id, context=context).partner_id.id
-                        else:
-                            #create the bank account, not linked to any partner. The reconciliation will link the partner manually
-                            #chosen at the bank statement final confirmation time.
-                            try:
-                                type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
-                                type_id = self.pool.get('res.partner.bank.type').browse(cr, uid, type_id, context=context)
-                                bank_code = type_id.code
-                            except ValueError:
-                                bank_code = 'bank'
-                            bank_account_id = self.pool.get('res.partner.bank').create(cr, uid, {'acc_number': str(line['counterpartyNumber']), 'state': bank_code}, context=context)
+                        bank_account_id, partner_id = self._detect_partner(cr, uid, str(line['counterpartyNumber']), identifying_field='acc_number', context=context)
                     if 'communication' in line and line['communication'] != '':
                         note.append(_('Communication') + ': ' + line['communication'])
-                    data = {
+                    line_data = {
                         'name': line['name'],
                         'note': "\n".join(note),
                         'date': line['entryDate'],
                         'amount': line['amount'],
                         'partner_id': partner_id,
-                        'statement_id': statement['id'],
                         'ref': structured_com,
                         'sequence': line['sequence'],
                         'bank_account_id': bank_account_id,
                     }
-                    self.pool.get('account.bank.statement.line').create(cr, uid, data, context=context)
+                    statement_line.append((0, 0, line_data))
             if statement['coda_note'] != '':
-                self.pool.get('account.bank.statement').write(cr, uid, [statement['id']], {'coda_note': statement['coda_note']}, context=context)
-        model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_bank_statement_tree')
-        action = self.pool[model].browse(cr, uid, action_id, context=context)
-        return {
-            'name': action.name,
-            'view_type': action.view_type,
-            'view_mode': action.view_mode,
-            'res_model': action.res_model,
-            'domain': action.domain,
-            'context': action.context,
-            'type': 'ir.actions.act_window',
-            'search_view_id': action.search_view_id.id,
-            'views': [(v.view_id.id, v.view_mode) for v in action.view_ids]
-        }
+                statement_data.update({'coda_note': statement['coda_note']})
+            statement_data.update({'journal_id': journal_id, 'line_ids': statement_line})
+        return [statement_data]
 
 
 def rmspaces(s):