From 2d9569cc18d47c0f9c29efaec78900ebefb0372d Mon Sep 17 00:00:00 2001 From: Arthur Maniet Date: Sun, 31 May 2015 14:58:04 +0200 Subject: [PATCH] [FIX] account: bank statement import - use a wizard to ask about creating a new bank account + journal - fix 'Import Statement' action from the dashboard - make l10n_be_coda new-api-compliant --- addons/account/account_journal_dashboard.py | 4 +- .../account_bank_statement_import.py | 139 +++++++++--------- .../wizard/journal_creation.py | 4 +- .../wizard/journal_creation.xml | 2 +- .../account_bank_statement_import_qif.py | 15 +- ...account_bank_statement_import_qif_view.xml | 8 +- addons/l10n_be/__openerp__.py | 1 - addons/l10n_be_coda/__openerp__.py | 4 +- .../wizard/account_coda_import.py | 27 ++-- 9 files changed, 100 insertions(+), 104 deletions(-) diff --git a/addons/account/account_journal_dashboard.py b/addons/account/account_journal_dashboard.py index a1b5716ba85..f7cdd726a3e 100644 --- a/addons/account/account_journal_dashboard.py +++ b/addons/account/account_journal_dashboard.py @@ -343,5 +343,7 @@ class account_journal(models.Model): action_name = 'action_account_bank_statement_import' ir_model_obj = self.pool['ir.model.data'] model, action_id = ir_model_obj.get_object_reference(self._cr, self._uid, 'account_bank_statement_import', action_name) - action = self.pool[model].read(self._cr, self._uid, action_id, context=self._context) + action = self.pool[model].read(self._cr, self._uid, action_id, context=self.env.context) + # Note: this drops action['context'], which is a dict stored as a string, which is not easy to update + action.update({'context': (u"{'journal_id': " + str(self.id) + u"}")}) return action diff --git a/addons/account_bank_statement_import/account_bank_statement_import.py b/addons/account_bank_statement_import/account_bank_statement_import.py index 893c1fae0ba..c9ca9c19388 100644 --- a/addons/account_bank_statement_import/account_bank_statement_import.py +++ b/addons/account_bank_statement_import/account_bank_statement_import.py @@ -30,25 +30,24 @@ class AccountBankStatementImport(models.TransientModel): def import_file(self): """ Process the file chosen in the wizard, create bank statement(s) and go to reconciliation. """ self.ensure_one() - rec = self.with_context(active_id=self.ids[0]) #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) data_file = self.data_file - # The appropriate implementation module returns the required data - currency_code, account_number, stmts_vals = rec._parse_file(base64.b64decode(data_file)) + # Let the appropriate implementation module parse the file and return the required data + # The active_id is passed in context in case an implementation module requires information about the wizard state (see QIF) + currency_code, account_number, stmts_vals = self.with_context(active_id=self.ids[0])._parse_file(base64.b64decode(data_file)) # Check raw data - rec._check_parsed_data(stmts_vals) - # Try to find the bank account and currency in odoo - currency_id, bank_account_id = rec._find_additional_data(currency_code, account_number) - # Find or create the bank journal - journal_id = rec._get_journal(currency_id, bank_account_id, account_number) - # Create the bank account if not already existing - if not bank_account_id and account_number: - rec._create_bank_account(account_number, journal_id=journal_id) + self._check_parsed_data(stmts_vals) + # Try to find the currency and journal in odoo + currency, journal, bank_account = self._find_additional_data(currency_code, account_number) + # If no journal found, ask the user about creating one + if not journal: + # The active_id is passed in context so the wizard can call import_file again once the journal is created + return self.with_context(active_id=self.ids[0])._journal_creation_wizard(currency, account_number, bank_account) # Prepare statement data to be used for bank statements creation - stmts_vals = rec._complete_stmts_vals(stmts_vals, journal_id, account_number) + stmts_vals = self._complete_stmts_vals(stmts_vals, journal, account_number) # Create the bank statements - statement_ids, notifications = rec._create_bank_statements(stmts_vals) + statement_ids, notifications = self._create_bank_statements(stmts_vals) # Finally dispatch to reconciliation interface action = self.env.ref('account.action_bank_reconcile_bank_statements') return { @@ -61,6 +60,24 @@ class AccountBankStatementImport(models.TransientModel): 'type': 'ir.actions.client', } + def _journal_creation_wizard(self, currency, account_number, bank_account): + """ 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': self.env.context['active_id'], + 'default_currency_id': currency and currency.id or False, + 'default_account_number': account_number, + 'bank_account_id': bank_account and bank_account.id or False, + 'default_name': _('Bank') + ' ' + account_number, + } + } + def _parse_file(self, data_file): """ Each module adding a file support must extends this method. It processes the file if it can, returns super otherwise, resulting in a chain of responsability. This method parses the given file and returns the data required by the bank statement import process, as specified below. @@ -102,83 +119,71 @@ class AccountBankStatementImport(models.TransientModel): def _find_additional_data(self, currency_code, account_number): """ Get the res.currency ID and the res.partner.bank ID """ - currency_id = False # So if no currency_code is provided, we'll use the company currency + company_currency = self.env.user.company_id.currency_id + journal_obj = self.env['account.journal'] + currency = None + if currency_code: currency = self.env['res.currency'].search([('name', '=ilike', currency_code)], limit=1) - company_currency = self.env.user.company_id.currency_id - if currency.id != company_currency.id: - currency_id = currency.id + if not currency: + raise osv.except_osv(_("No currency found matching '%s'.") % currency_code) + if currency == company_currency: + currency = False - bank_account_id = None + bank_account = None if account_number and len(account_number) > 4: - account_number = account_number.replace(' ', '').replace('-', '') - self.env.cr.execute("select id from res_partner_bank where replace(replace(acc_number,' ',''),'-','') = %s", (account_number,)) - bank_account_ids = [id[0] for id in self.env.cr.fetchall()] - bank_account_ids = self.env['res.partner.bank'].search([('id', 'in', bank_account_ids)], limit=1) - if bank_account_ids: - bank_account_id = bank_account_ids.id - - return currency_id, bank_account_id - - def _get_journal(self, currency_id, bank_account_id, account_number): - """ Find or create the journal """ - ResPartnerBank = self.env['res.partner.bank'] + bank_account = self.env['res.partner.bank'].search([('acc_number', '=', account_number)], limit=1) # Find the journal from context or bank account - journal_id = self._context.get('journal_id') - if bank_account_id: - bank_account = ResPartnerBank.browse(bank_account_id) - if journal_id: - if bank_account.journal_id.id and bank_account.journal_id.id != journal_id: + journal = journal_obj.browse(self._context.get('journal_id', [])) + if bank_account: + if journal: + if bank_account.journal_id and bank_account.journal_id != journal: raise UserError(_('The account of this statement is linked to another journal.')) - if not bank_account.journal_id.id: - bank_account.write({'journal_id': journal_id}) + if not bank_account.journal_id: + bank_account.write({'journal_id': journal.id}) else: - if bank_account.journal_id.id: - journal_id = bank_account.journal_id.id + if bank_account.journal_id: + journal = bank_account.journal_id - # If importing into an existing journal, its currency must be the same as the bank statement - if journal_id: - journal_currency_id = self.env['account.journal'].browse(journal_id).currency_id.id - 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 importing into an existing journal + if journal: + # The bank account cannot belong to another journal + if not bank_account and account_number: + journal_account = self.env['res.partner.bank'].search([('journal_id', '=', journal.id)], limit=1) + if journal_account: + raise UserError(_('You are importing a file from account %s while the account of journal %s is %s.') % (account_number, journal.name, journal_account.acc_number)) - # If there is no journal, create one (and its account) - if not journal_id and account_number: - company = self.env.user.company_id - journal_vals = self.env['account.journal']._prepare_bank_journal(company, {'account_type': 'bank', 'acc_name': account_number, 'currency_id': currency_id}) - journal_id = self.env['account.journal'].create(journal_vals).id - if bank_account_id: - bank_account.write({'journal_id': journal_id}) + # Its currency must be the same as the bank statement + journal_currency = journal.currency_id + if currency == None: + currency = journal_currency + if currency and currency != journal_currency: + statement_cur_code = currency == False and company_currency.name or currency.name + journal_cur_code = not journal_currency and company_currency.name or journal_currency.name + raise UserError(_('The currency of the bank statement (%s) is not the same as the currency of the journal (%s) !') % (statement_cur_code, journal_cur_code)) - # If we couldn't find/create a journal, everything is lost - if not journal_id: + # If we couldn't find / can't create a journal, everything is lost + if not journal and not account_number: raise UserError(_('Cannot find in which journal import this statement. Please manually select a journal.')) - return journal_id - def _create_bank_account(self, account_number, journal_id=False): + return currency, journal, bank_account + + def _create_bank_account(self, account_number): try: bank_type = self.env.ref('bank.bank_normal') bank_code = bank_type.code except ValueError: bank_code = 'bank' account_number = account_number.replace(' ', '').replace('-', '') - vals_acc = { + return self.env['res.partner.bank'].create({ 'acc_number': account_number, 'state': bank_code, - } - # Odoo users bank accounts (which we import statement from) have company_id and journal_id set - # while 'counterpart' bank accounts (from which statement transactions originate) don't. - if journal_id: - vals_acc['journal_id'] = journal_id - vals_acc['company_id'] = self.env.user.company_id.id - vals_acc['partner_id'] = self.env.user.company_id.partner_id.id + }) - return self.env['res.partner.bank'].create(vals_acc) - - def _complete_stmts_vals(self, stmts_vals, journal_id, account_number): + def _complete_stmts_vals(self, stmts_vals, journal, account_number): for st_vals in stmts_vals: - st_vals['journal_id'] = journal_id + st_vals['journal_id'] = journal.id for line_vals in st_vals['transactions']: unique_import_id = line_vals.get('unique_import_id') diff --git a/addons/account_bank_statement_import/wizard/journal_creation.py b/addons/account_bank_statement_import/wizard/journal_creation.py index d49fde7faf3..3acd180ac50 100644 --- a/addons/account_bank_statement_import/wizard/journal_creation.py +++ b/addons/account_bank_statement_import/wizard/journal_creation.py @@ -19,7 +19,7 @@ class account_bank_statement_import_journal_creation(models.TransientModel): currency_id = wiz.currency_id.id account_number = wiz.account_number - bank_account_id = self.env._context.get('bank_account_id') + bank_account_id = self.env.context.get('bank_account_id') if bank_account_id: vals = {'currency_id': currency_id, 'acc_name': account_number, 'account_type': 'bank'} vals_journal = journal_obj._prepare_bank_journal(company, vals) @@ -38,5 +38,5 @@ class account_bank_statement_import_journal_creation(models.TransientModel): self.env['res.partner.bank'].create(res_partner_bank_vals) # Finish the statement import - statement_import_transient = import_wiz_obj.browse(self.env._context['statement_import_transient_id']) + statement_import_transient = import_wiz_obj.browse(self.env.context['statement_import_transient_id']) return statement_import_transient.import_file() diff --git a/addons/account_bank_statement_import/wizard/journal_creation.xml b/addons/account_bank_statement_import/wizard/journal_creation.xml index 4f9c53af1a2..3894991eddb 100644 --- a/addons/account_bank_statement_import/wizard/journal_creation.xml +++ b/addons/account_bank_statement_import/wizard/journal_creation.xml @@ -11,7 +11,7 @@

Just click OK to create the account/journal and finish the import. If this was a mistake, hit cancel to abort the import.

- +