[IMP] account_bank_statement_import: ask for confirmation before creating a journal

In previous versions the system would simply refuse to import
a bank statement if the corresponding journal/account did
not exist.
As of 9.0 the system can create them automatically, but
should not do that without asking for confirmation first,
to avoid user mistakes with dangerous consequences.

Closes #6023
This commit is contained in:
Arthur Maniet
2015-04-10 18:23:32 +02:00
committed by Olivier Dony
parent 8c65573885
commit bc33b8dd04
7 changed files with 122 additions and 36 deletions
@@ -1,3 +1,5 @@
# -*- encoding: utf-8 -*-
import account_bank_statement_import
import wizard
@@ -9,7 +9,8 @@
'description' : """Generic Wizard to Import Bank Statements. Includes the import of files in .OFX format""",
'data' : [
'account_bank_statement_import_view.xml',
'account_import_tip_data.xml'
'account_import_tip_data.xml',
'wizard/journal_creation.xml',
],
'demo': [
'demo/fiscalyear_period.xml',
@@ -37,21 +37,47 @@ class account_bank_statement_import(osv.TransientModel):
context = {}
#set the active_id in the context, so that any extension module could
#reuse the fields chosen in the wizard if needed (see .QIF for example)
context.update({'active_id': ids[0]})
ctx = dict(context)
ctx['active_id'] = ids[0]
data_file = self.browse(cr, uid, ids[0], context=context).data_file
data_file = self.browse(cr, uid, ids[0], context=ctx).data_file
# The appropriate implementation module returns the required data
currency_code, account_number, stmts_vals = self._parse_file(cr, uid, base64.b64decode(data_file), context=context)
currency_code, account_number, stmts_vals = self._parse_file(cr, uid, base64.b64decode(data_file), context=ctx)
# Check raw data
self._check_parsed_data(cr, uid, stmts_vals, context=context)
self._check_parsed_data(cr, uid, stmts_vals, context=ctx)
# Try to find the bank account and currency in odoo
currency_id, bank_account_id = self._find_additional_data(cr, uid, currency_code, account_number, context=context)
# Find or create the bank journal
journal_id = self._get_journal(cr, uid, currency_id, bank_account_id, account_number, context=context)
# Create the bank account if not already existing
if not bank_account_id and account_number:
self._create_bank_account(cr, uid, account_number, journal_id=journal_id, partner_id=uid, context=context)
currency_id, bank_account_id = self._find_additional_data(cr, uid, currency_code, account_number, context=ctx)
# Try to find the journal
journal_id = self._get_journal(cr, uid, currency_id, bank_account_id, account_number, context=ctx)
# If no journal found, ask the user about creating one
if not journal_id:
return self._journal_creation_wizard(cr, uid, currency_id, account_number, bank_account_id, context=ctx)
# Or directly finish the import
return self._finalize_import(cr, uid, bank_account_id, account_number, journal_id, stmts_vals, context=ctx)
def _journal_creation_wizard(self, cr, uid, currency_id, account_number, bank_account_id, context=None):
""" Calls a wizard that allows the user to accept/refuse journal creation """
return {
'name': _('Journal Creation'),
'type': 'ir.actions.act_window',
'res_model': 'account.bank.statement.import.journal.creation',
'view_type': 'form',
'view_mode': 'form',
'target': 'new',
'context': {
'statement_import_transient_id': context['active_id'],
'default_currency_id': currency_id,
'default_account_number': account_number,
'bank_account_id': bank_account_id,
'default_name': _('Bank') + ' ' + account_number,
}
}
def _finalize_import(self, cr, uid, bank_account_id, account_number, journal_id, stmts_vals, context=None):
""" This part is separated from import_file so it can be called via the joutnal creation wizard
No CUD can happen before this method is called, so not calling it is like aborting the import.
"""
# Prepare statement data to be used for bank statements creation
stmts_vals = self._complete_stmts_vals(cr, uid, stmts_vals, journal_id, account_number, context=context)
# Create the bank statements
@@ -153,31 +179,12 @@ class account_bank_statement_import(osv.TransientModel):
if currency_id and currency_id != journal_currency_id:
raise UserError(_('The currency of the bank statement is not the same as the currency of the journal !'))
# If there is no journal, create one (and its account)
if not journal_id and account_number:
journal_id = self._create_journal(cr, uid, currency_id, account_number, context=context)
if bank_account_id:
bank_pool.write(cr, uid, [bank_account_id], {'journal_id': journal_id}, context=context)
# If we couldn't find/create a journal, everything is lost
if not journal_id:
# If we couldn't find a journal and can't create one, everything is lost
if not journal_id and not account_number:
raise UserError(_('Cannot find in which journal import this statement. Please manually select a journal.'))
return journal_id
def _create_journal(self, cr, uid, currency_id, account_number, context=None):
""" Create a journal and its account """
wmca_pool = self.pool.get('wizard.multi.charts.accounts')
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
vals_account = {'currency_id': currency_id, 'acc_name': account_number, 'account_type': 'bank', 'currency_id': currency_id}
vals_account = wmca_pool._prepare_bank_account(cr, uid, company, vals_account, context=context)
account_id = self.pool.get('account.account').create(cr, uid, vals_account, context=context)
vals_journal = {'currency_id': currency_id, 'acc_name': _('Bank') + ' ' + account_number, 'account_type': 'bank'}
vals_journal = wmca_pool._prepare_bank_journal(cr, uid, company, vals_journal, account_id, context=context)
return self.pool.get('account.journal').create(cr, uid, vals_journal, context=context)
def _create_bank_account(self, cr, uid, account_number, journal_id=False, partner_id=False, context=None):
try:
type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
@@ -245,7 +252,7 @@ class account_bank_statement_import(osv.TransientModel):
else:
ignored_statement_lines_import_ids.append(line_vals['unique_import_id'])
if len(filtered_st_lines) > 0:
# Remove values that won't be used to create records
# Remove values that won't be used to create records
st_vals.pop('transactions', None)
for line_vals in filtered_st_lines:
line_vals.pop('account_number', None)
@@ -270,4 +277,3 @@ class account_bank_statement_import(osv.TransientModel):
}]
return statement_ids, notifications
@@ -0,0 +1 @@
import journal_creation
@@ -0,0 +1,42 @@
# -*- coding: utf-8 -*-
from openerp.osv import fields, osv
from openerp.tools.translate import _
class account_bank_statement_import_journal_creation(osv.TransientModel):
_name = 'account.bank.statement.import.journal.creation'
_description = 'Import Bank Statement Journal Creation Wizard'
_columns = {
'name': fields.char('Journal Name', required=True),
'currency_id': fields.many2one('res.currency', 'Currency', readonly=True),
'account_number': fields.char('Account Number', readonly=True),
}
def create_journal(self, cr, uid, ids, context=None):
bank_account_id = context['bank_account_id']
wmca_pool = self.pool.get('wizard.multi.charts.accounts')
import_wiz_obj = self.pool['account.bank.statement.import']
company = self.pool.get('res.users').browse(cr, uid, uid, context=context).company_id
wiz = self.browse(cr, uid, ids, context=context)[0]
currency_id = wiz.currency_id.id
account_number = wiz.account_number
# Create the account.account
vals_account = {'currency_id': currency_id, 'acc_name': account_number, 'account_type': 'bank', 'currency_id': currency_id}
vals_account = wmca_pool._prepare_bank_account(cr, uid, company, vals_account, context=context)
account_id = self.pool.get('account.account').create(cr, uid, vals_account, context=context)
# Create the account.journal
name = wiz.name
vals_journal = {'currency_id': currency_id, 'acc_name': name, 'account_type': 'bank'}
vals_journal = wmca_pool._prepare_bank_journal(cr, uid, company, vals_journal, account_id, context=context)
journal_id = self.pool.get('account.journal').create(cr, uid, vals_journal, context=context)
if bank_account_id:
self.pool.get('res.partner.bank').write(cr, uid, [bank_account_id], {'journal_id': journal_id}, context=context)
# Create the bank account if not already existing
elif not bank_account_id and account_number:
import_wiz_obj._create_bank_account(cr, uid, account_number, journal_id=journal_id, partner_id=uid, context=context)
# Finish the statement import
statement_import_transient = import_wiz_obj.browse(cr, uid, context['statement_import_transient_id'], context=context)
return statement_import_transient.import_file()
@@ -0,0 +1,27 @@
<?xml version="1.0" ?>
<openerp>
<data>
<record id="account_bank_statement_import_journal_creation_view" model="ir.ui.view">
<field name="name">Journal Creation</field>
<field name="model">account.bank.statement.import.journal.creation</field>
<field name="arch" type="xml">
<form string="Journal Creation">
<p>The account of the statement you are importing is not yet recorded in Odoo. In order to proceed with the import, you need to create a bank account and journal using this form.</p>
<p>Just click OK to create the account/journal and finish the import. If this was a mistake, hit cancel to abort the import.</p>
<group>
<field name="name"/>
<field name="currency_id"/>
<field name="account_number"/>
</group>
<footer>
<button name="create_journal" string="OK" type="object" class="oe_highlight"/>
or
<button string="Cancel" class="oe_link" special="cancel"/>
</footer>
</form>
</field>
</record>
</data>
</openerp>
@@ -17,13 +17,20 @@ class TestOfxFile(TransactionCase):
#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
creation_wiz_obj = self.registry('account.bank.statement.import.journal.creation')
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(
data_file=ofx_file,
))
self.statement_import_model.import_file(cr, uid, [bank_statement_id])
statement_id = self.bank_statement_model.search(cr, uid, [('name', '=', '000000123')])[0]
res = self.statement_import_model.import_file(cr, uid, [bank_statement_id])
self.assertEquals(res['res_model'], 'account.bank.statement.import.journal.creation', 'boom')
ctx = res.get('context', {}).copy()
wiz_id = creation_wiz_obj.create(cr, uid, {}, context=ctx)
wiz = creation_wiz_obj.browse(cr, uid, [wiz_id], context=ctx)
wiz.create_journal()
statement_id = self.bank_statement_model.search(cr, uid, [('name', '=', '000000123')])
bank_st_record = self.bank_statement_model.browse(cr, uid, statement_id)
self.assertEquals(bank_st_record.balance_start, 2516.56)
self.assertEquals(bank_st_record.balance_end_real, 2156.56)