diff --git a/addons/account/__openerp__.py b/addons/account/__openerp__.py
index b1592ba5bec..f5322dc2a2c 100644
--- a/addons/account/__openerp__.py
+++ b/addons/account/__openerp__.py
@@ -41,12 +41,12 @@ You could use this simplified accounting in case you work with an (external) acc
'views/product_view.xml',
'views/account_analytic_view.xml',
'views/company_view.xml',
- 'views/account_bank_view.xml',
'views/res_config_view.xml',
'views/account_tip_data.xml',
'views/account.xml',
'views/report_invoice.xml',
'report/account_invoice_report_view.xml',
+ 'report/inherited_layouts.xml',
'views/account_journal_dashboard_view.xml',
],
'demo': [
diff --git a/addons/account/models/__init__.py b/addons/account/models/__init__.py
index a31840bb76e..b4855fb482f 100644
--- a/addons/account/models/__init__.py
+++ b/addons/account/models/__init__.py
@@ -5,7 +5,6 @@ import account
import account_payment
import account_invoice
import account_bank_statement
-import account_bank
import account_move
import chart_template
import account_analytic_line
diff --git a/addons/account/models/account.py b/addons/account/models/account.py
index f3a1228b58d..95e1f061165 100644
--- a/addons/account/models/account.py
+++ b/addons/account/models/account.py
@@ -6,7 +6,7 @@ import math
from openerp.osv import expression
from openerp.tools.float_utils import float_round as round
from openerp.tools import DEFAULT_SERVER_DATETIME_FORMAT
-from openerp.exceptions import UserError
+from openerp.exceptions import UserError, ValidationError
from openerp import api, fields, models, _
@@ -189,7 +189,7 @@ class AccountJournal(models.Model):
return self.env.ref('account.account_payment_method_manual_out')
name = fields.Char(string='Journal Name', required=True)
- code = fields.Char(string='Sequence Prefix', size=5, required=True, help="The journal entries of this journal will be named using this prefix.")
+ code = fields.Char(string='Short Code', size=5, required=True, help="The journal entries of this journal will be named using this prefix.")
type = fields.Selection([
('sale', 'Sale'),
('purchase', 'Purchase'),
@@ -240,6 +240,13 @@ class AccountJournal(models.Model):
profit_account_id = fields.Many2one('account.account', string='Profit Account', domain=[('deprecated', '=', False)], help="Used to register a profit when the ending balance of a cash register differs from what the system computes")
loss_account_id = fields.Many2one('account.account', string='Loss Account', domain=[('deprecated', '=', False)], help="Used to register a loss when the ending balance of a cash register differs from what the system computes")
+ # Bank journals fields
+ bank_account_id = fields.Many2one('res.partner.bank', string="Bank Account", ondelete='restrict')
+ display_on_footer = fields.Boolean("Show in Invoices Footer", help="Display this bank account on the footer of printed documents like invoices and sales orders.")
+ bank_statements_source = fields.Selection([('manual', 'Record Manually')], string='Bank Feeds')
+ bank_acc_number = fields.Char(related='bank_account_id.acc_number')
+ bank_id = fields.Many2one('res.bank', related='bank_account_id.bank_id')
+
_sql_constraints = [
('code_company_uniq', 'unique (code, name, company_id)', 'The code and name of the journal must be unique per company !'),
]
@@ -253,6 +260,17 @@ class AccountJournal(models.Model):
if self.default_debit_account_id and not self.default_debit_account_id.currency_id.id == self.currency_id.id:
raise UserError(_('Configuration error!\nThe currency of the journal should be the same than the default debit account.'))
+ @api.one
+ @api.constrains('type', 'bank_account_id')
+ def _check_bank_account(self):
+ if self.type == 'bank' and self.bank_account_id:
+ if self.bank_account_id.company_id != self.company_id:
+ raise ValidationError(_('The bank account of a bank journal must belong to the same company (%s).') % self.company_id.name)
+ # A bank account can belong to a customer/supplier, in which case their partner_id is the customer/supplier.
+ # Or they are part of a bank journal and their partner_id must be the company's partner_id.
+ if self.bank_account_id.partner_id != self.company_id.partner_id:
+ raise ValidationError(_('The holder of a journal\'s bank account must be the company (%s).') % self.company_id.name)
+
@api.onchange('default_debit_account_id')
def onchange_debit_account_id(self):
if not self.default_credit_account_id:
@@ -285,7 +303,14 @@ class AccountJournal(models.Model):
if journal.refund_sequence_id:
new_prefix = self._get_sequence_prefix(vals['code'], refund=True)
journal.refund_sequence_id.write({'prefix': new_prefix})
- return super(AccountJournal, self).write(vals)
+ result = super(AccountJournal, self).write(vals)
+
+ # Create the bank_account_id if necessary
+ if 'bank_acc_number' in vals:
+ for journal in self.filtered(lambda r: r.type == 'bank' and not r.bank_account_id):
+ journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id'))
+
+ return result
@api.model
def _get_sequence_prefix(self, code, refund=False):
@@ -349,57 +374,55 @@ class AccountJournal(models.Model):
'company_id': company.id,
}
- @api.model
- def _prepare_bank_journal(self, company, line):
- '''
- This function prepares the value to use for the creation of a bank journal created through the wizard of
- generating COA from templates.
-
- :param company: company for which the wizard is running
- :param line: dictionary containing the values encoded by the user related to his bank account with keys
- - acc_name (char): name of the bank account
- - account_type (char): kind of liquidity journal to create. Either 'bank' or 'cash'
- - currency_id (int): id of the currency related to this account if its different than the company currency (False otherwise)
- :return: mapping of field names and values
- :rtype: dict
- '''
- # we need to loop to find next number for journal code
- for num in xrange(1, 100):
- # journal_code has a maximal size of 5, hence we can enforce the boundary num < 100
- journal_code = line.get('account_type', 'bank') == 'cash' and 'CSH' or 'BNK'
- journal_code += str(num)
- journal = self.env['account.journal'].search([('code', '=', journal_code), ('company_id', '=', company.id)], limit=1)
- if not journal:
- break
- else:
- raise UserError(_('Cannot generate an unused journal code.'))
-
- return {
- 'name': line['acc_name'],
- 'code': journal_code,
- 'type': line.get('account_type', 'bank'),
- 'company_id': company.id,
- 'analytic_journal_id': False,
- 'currency_id': line.get('currency_id', False),
- 'show_on_dashboard': True,
- }
-
@api.model
def create(self, vals):
+ company_id = vals.get('company_id', self.env.user.company_id.id)
if vals.get('type') in ('bank', 'cash'):
+ # If no code provided, loop to find next available journal code
+ if not vals.get('code'):
+ for num in xrange(1, 100):
+ # journal_code has a maximal size of 5, hence we can enforce the boundary num < 100
+ journal_code = (vals['type'] == 'cash' and 'CSH' or 'BNK') + str(num)
+ journal = self.env['account.journal'].search([('code', '=', journal_code), ('company_id', '=', company_id)], limit=1)
+ if not journal:
+ vals['code'] = journal_code
+ break
+ else:
+ raise UserError(_("Cannot generate an unused journal code. Please fill the 'Shortcode' field."))
+
+ # Create a default debit/credit account if not given
default_account = vals.get('default_debit_account_id') or vals.get('default_credit_account_id')
if not default_account:
- company = self.env['res.company'].browse(vals['company_id'])
+ company = self.env['res.company'].browse(company_id)
account_vals = self._prepare_liquidity_account(vals.get('name'), company, vals.get('currency_id'), vals.get('type'))
default_account = self.env['account.account'].create(account_vals)
vals['default_debit_account_id'] = default_account.id
vals['default_credit_account_id'] = default_account.id
+
# We just need to create the relevant sequences according to the chosen options
if not vals.get('sequence_id'):
vals.update({'sequence_id': self.sudo()._create_sequence(vals).id})
if vals.get('refund_sequence') and not vals.get('refund_sequence_id'):
vals.update({'refund_sequence_id': self.sudo()._create_sequence(vals, refund=True).id})
- return super(AccountJournal, self).create(vals)
+
+ journal = super(AccountJournal, self).create(vals)
+
+ # Create the bank_account_id if necessary
+ if journal.type == 'bank' and not journal.bank_account_id and vals.get('bank_acc_number'):
+ journal.set_bank_account(vals.get('bank_acc_number'), vals.get('bank_id'))
+
+ return journal
+
+ def set_bank_account(self, acc_number, bank_id=None):
+ """ Create a res.partner.bank and set it as value of the field bank_account_id """
+ self.ensure_one()
+ self.bank_account_id = self.env['res.partner.bank'].create({
+ 'acc_number': acc_number,
+ 'bank_id': bank_id,
+ 'company_id': self.company_id.id,
+ 'currency_id': self.currency_id.id,
+ 'partner_id': self.company_id.partner_id.id,
+ }).id
@api.multi
@api.depends('name', 'currency_id', 'company_id', 'company_id.currency_id')
@@ -419,6 +442,19 @@ class AccountJournal(models.Model):
journal.at_least_one_outbound = bool(len(self.outbound_payment_method_ids))
+class ResPartnerBank(models.Model):
+ _inherit = "res.partner.bank"
+
+ journal_id = fields.One2many('account.journal', 'bank_account_id', domain=[('type', '=', 'bank')], string='Account Journal', readonly=True,
+ help="The accounting journal corresponding to this bank account.")
+
+ @api.one
+ @api.constrains('journal_id')
+ def _check_journal_id(self):
+ if len(self.journal_id) > 1:
+ raise ValidationError(_('A bank account can anly belong to one journal.'))
+
+
#----------------------------------------------------------
# Tax
#----------------------------------------------------------
diff --git a/addons/account/models/account_bank.py b/addons/account/models/account_bank.py
deleted file mode 100644
index 96b69d81bab..00000000000
--- a/addons/account/models/account_bank.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# -*- coding: utf-8 -*-
-
-from openerp import api, fields, models
-
-
-class Bank(models.Model):
- _inherit = "res.partner.bank"
-
- journal_id = fields.Many2one('account.journal', string='Account Journal',
- help="This journal will be created automatically for this bank account when you save the record")
-
- @api.model
- def create(self, data):
- result = super(Bank, self).create(data)
- result.post_write()
- return result
-
- @api.multi
- def write(self, data):
- result = super(Bank, self).write(data)
- self.post_write()
- return result
-
- @api.model
- def _prepare_name(self, bank):
- "Return the name to use when creating a bank journal"
- name = bank.bank_name + ' ' if bank.bank_name else ''
- name += bank.acc_number
- return name
-
- @api.multi
- def post_write(self):
- JournalObj = self.env['account.journal']
- for bank in self:
- # Create a journal for the bank account if it belongs to the company.
- if bank.company_id and not bank.journal_id:
- journal_vals = JournalObj._prepare_bank_journal(bank.company_id, {'acc_name': self._prepare_name(bank), 'currency_id': bank.currency_id.id, 'account_type': 'bank'})
- journal = JournalObj.create(journal_vals)
- missing_vals = {'journal_id': journal.id}
- if not bank.partner_id:
- missing_vals['partner_id'] = bank.company_id.partner_id.id
- if not bank.owner_name:
- missing_vals['owner_name'] = bank.company_id.partner_id.name
- bank.write(missing_vals)
diff --git a/addons/account/models/account_journal_dashboard.py b/addons/account/models/account_journal_dashboard.py
index 27e3bc8fb77..d4a8add628b 100644
--- a/addons/account/models/account_journal_dashboard.py
+++ b/addons/account/models/account_journal_dashboard.py
@@ -187,7 +187,8 @@ class account_journal(models.Model):
'sum_waiting': formatLang(self.env, sum_waiting or 0.0, currency_obj=self.currency_id or self.company_id.currency_id),
'sum_late': formatLang(self.env, sum_late or 0.0, currency_obj=self.currency_id or self.company_id.currency_id),
'currency_id': self.currency_id and self.currency_id.id or self.company_id.currency_id.id,
- 'show_import': True if self.type in ['bank', 'cash'] and len(ac_bnk_stmt) == 0 and last_balance == 0 else False,
+ 'no_statement': bool(self.type in ['bank', 'cash'] and len(ac_bnk_stmt) == 0),
+ 'bank_statements_source': self.bank_statements_source,
'title': title,
}
@@ -220,7 +221,7 @@ class account_journal(models.Model):
}
@api.multi
- def create_cash_bank(self):
+ def create_cash_statement(self):
ctx = self._context.copy()
ctx.update({'journal_id': self.id, 'default_journal_id': self.id, 'default_journal_type': 'cash'})
return {
@@ -337,13 +338,12 @@ class account_journal(models.Model):
return action
@api.multi
- def import_statement(self):
- """return action to import bank/cash statements. This button should be called only on journals with type =='bank'"""
- model = 'account.bank.statement'
- 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.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"}")})
+ def create_bank_statement(self):
+ """return action to create a bank statements. This button should be called only on journals with type =='bank'"""
+ self.bank_statements_source = 'manual'
+ action = self.env.ref('account.action_bank_statement_tree').read()[0]
+ action.update({
+ 'views': [[False, 'form']],
+ 'context': "{'default_journal_id': " + str(self.id) + "}",
+ })
return action
diff --git a/addons/account/models/chart_template.py b/addons/account/models/chart_template.py
index 12b4433bd70..d9eebe31e1c 100644
--- a/addons/account/models/chart_template.py
+++ b/addons/account/models/chart_template.py
@@ -751,42 +751,21 @@ class WizardMultiChartsAccounts(models.TransientModel):
def _create_bank_journals_from_o2m(self, company, acc_template_ref):
'''
This function creates bank journals and its accounts for each line encoded in the field bank_account_ids of the
- wizard.
+ wizard (which is currently only used to create a default bank and cash journal when the CoA is installed).
- :param company_id: the id of the company for which the wizard is running.
+ :param company: the company for which the wizard is running.
:param acc_template_ref: the dictionary containing the mapping between the ids of account templates and the ids
of the accounts that have been generated from them.
- :return: True
'''
self.ensure_one()
- # Build a list with all the data to process
- journal_data = []
- if self.bank_account_ids:
- for acc in self.bank_account_ids:
- vals = {
- 'acc_name': acc.acc_name,
- 'account_type': acc.account_type,
- 'currency_id': acc.currency_id.id,
- }
- journal_data.append(vals)
-
- for line in journal_data:
- if line['account_type'] == 'bank':
- #create the bank account that will trigger the journal and account.account creation
- res_partner_bank_vals = {
- 'acc_number': line['acc_name'],
- 'currency_id': line['currency_id'],
- 'company_id': company.id,
- 'owner_name': company.partner_id.name,
- 'partner_id': company.partner_id.id,
- 'footer': True
- }
- self.env['res.partner.bank'].create(res_partner_bank_vals)
- else:
- #create the cash journal that will trigger the account.account creation
- vals_journal = self.env['account.journal']._prepare_bank_journal(company, line)
- self.env['account.journal'].create(vals_journal)
- return True
+ # Create the journals that will trigger the account.account creation
+ for acc in self.bank_account_ids:
+ self.env['account.journal'].create({
+ 'name': acc.acc_name,
+ 'type': acc.account_type,
+ 'company_id': company.id,
+ 'currency_id': acc.currency_id.id,
+ })
class AccountBankAccountsWizard(models.TransientModel):
diff --git a/addons/account/models/company.py b/addons/account/models/company.py
index 0b3c0a8d1a9..d329003480b 100644
--- a/addons/account/models/company.py
+++ b/addons/account/models/company.py
@@ -34,6 +34,8 @@ class ResCompany(models.Model):
property_stock_account_input_categ_id = fields.Many2one('account.account', oldname="property_stock_account_input_categ")
property_stock_account_output_categ_id = fields.Many2one('account.account', oldname="property_stock_account_output_categ")
property_stock_valuation_account_id = fields.Many2one('account.account')
+ bank_journal_ids = fields.One2many('account.journal', 'company_id', domain=[('type', '=', 'bank')], string='Bank Journals')
+
@api.multi
def compute_fiscalyear_dates(self, date):
diff --git a/addons/account/models/res_config.py b/addons/account/models/res_config.py
index da44469b2cb..dc19a8dd3ac 100644
--- a/addons/account/models/res_config.py
+++ b/addons/account/models/res_config.py
@@ -174,14 +174,9 @@ class AccountConfigSettings(models.TransientModel):
return True
@api.multi
- def open_company_form(self):
- return {
- 'type': 'ir.actions.act_window',
- 'name': 'Configure your Company',
- 'res_model': 'res.company',
- 'res_id': self.company_id.id,
- 'view_mode': 'form',
- }
+ def open_bank_accounts(self):
+ action_rec = self.env['ir.model.data'].xmlid_to_object('account.action_account_bank_journal_form')
+ return action_rec.read([])[0]
@api.multi
def set_transfer_account(self):
diff --git a/addons/account/report/inherited_layouts.xml b/addons/account/report/inherited_layouts.xml
new file mode 100644
index 00000000000..290c1ba3a23
--- /dev/null
+++ b/addons/account/report/inherited_layouts.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
•
+
():
+
+
+
+
+
+
+
+
+
diff --git a/addons/account/static/src/less/account_journal_dashboard.less b/addons/account/static/src/less/account_journal_dashboard.less
index e0b15be344c..5e86c31d237 100644
--- a/addons/account/static/src/less/account_journal_dashboard.less
+++ b/addons/account/static/src/less/account_journal_dashboard.less
@@ -6,6 +6,10 @@
min-width: inherit;
}
+ button {
+ margin-bottom: 5px;
+ }
+
.o_kanban_card_settings {
padding: 8px;
diff --git a/addons/account/test/account_bank_statement.yml b/addons/account/test/account_bank_statement.yml
index cadb1f2fcd3..bd668e07a13 100644
--- a/addons/account/test/account_bank_statement.yml
+++ b/addons/account/test/account_bank_statement.yml
@@ -1,13 +1,6 @@
-
!context
journal_type: 'bank'
--
- We create a new bank with the company as partner in order to be sure to have at least one bank journal
--
- !record {model: res.partner.bank, id: test_bank}:
- acc_number: BE123456789
- bank_name: BNP Test bank
- partner_id: base.main_partner
-
In order to test Bank Statement feature of account I create a bank statement line and confirm it and check it's move created
-
diff --git a/addons/account/test/account_minimal_test.xml b/addons/account/test/account_minimal_test.xml
index 2d495188db0..9760eb53757 100644
--- a/addons/account/test/account_minimal_test.xml
+++ b/addons/account/test/account_minimal_test.xml
@@ -237,6 +237,12 @@
+
+ 987654321
+ bank
+ Bank
+
+ Bank - TestTBNK
@@ -244,6 +250,7 @@
+ Cash - Test
@@ -271,6 +278,12 @@
+
+ 123456789
+ bank
+ Bank US
+
+ USD Bank - TestTUBK
@@ -278,6 +291,7 @@
+
diff --git a/addons/account/tests/test_account_customer_invoice.py b/addons/account/tests/test_account_customer_invoice.py
index 0b79b47a0d9..565057d733d 100644
--- a/addons/account/tests/test_account_customer_invoice.py
+++ b/addons/account/tests/test_account_customer_invoice.py
@@ -8,13 +8,11 @@ class TestAccountCustomerInvoice(AccountTestUsers):
# I will create bank detail with using manager access rights
# because account manager can only create bank details.
self.res_partner_bank_0 = self.env['res.partner.bank'].sudo(self.account_manager.id).create(dict(
- state='bank',
+ acc_type='bank',
company_id=self.main_company.id,
partner_id=self.main_partner.id,
acc_number='123456789',
- footer=True,
- bank=self.main_bank.id,
- bank_name=self.main_bank.name,
+ bank_id=self.main_bank.id,
))
# Test with that user which have rights to make Invoicing and payment and who is accountant.
diff --git a/addons/account/tests/test_payment.py b/addons/account/tests/test_payment.py
index fba65d6f54c..00fcc9d7d3c 100644
--- a/addons/account/tests/test_payment.py
+++ b/addons/account/tests/test_payment.py
@@ -26,15 +26,11 @@ class TestPayment(AccountingTestCase):
self.account_payable = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_payable').id)], limit=1)
self.account_revenue = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1)
- self.bank_euro = self.env['res.partner.bank'].create({'acc_number': '0123456789', 'bank_name': 'Test Bank', 'company_id': self.env.user.company_id.id})
- self.bank_journal_euro = self.bank_euro.journal_id
+ self.bank_journal_euro = self.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'})
self.account_eur = self.bank_journal_euro.default_debit_account_id
- self.bank_usd = self.env['res.partner.bank'].create({'acc_number': '0123456789', 'bank_name': 'Test Bank USD', 'company_id': self.env.user.company_id.id})
- self.bank_journal_usd = self.bank_usd.journal_id
+ self.bank_journal_usd = self.env['account.journal'].create({'name': 'Bank US', 'type': 'bank', 'code': 'BNK68', 'currency_id': self.currency_usd_id})
self.account_usd = self.bank_journal_usd.default_debit_account_id
- self.account_usd.write({'currency_id': self.currency_usd_id})
- self.bank_journal_usd.write({'currency_id': self.currency_usd_id})
self.transfer_account = self.env['res.users'].browse(self.env.uid).company_id.transfer_account_id
self.diff_income_account = self.env['res.users'].browse(self.env.uid).company_id.income_currency_exchange_account_id
diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py
index e155923e20a..a11987dae07 100644
--- a/addons/account/tests/test_reconciliation.py
+++ b/addons/account/tests/test_reconciliation.py
@@ -28,16 +28,12 @@ class TestReconciliation(AccountingTestCase):
self.account_rsa = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_payable').id)], limit=1)
self.product = self.env.ref("product.product_product_4")
- self.bank_euro = self.env['res.partner.bank'].create({'acc_number': 'Reconciliation test', 'bank_name': 'Test Bank', 'company_id': self.env.user.company_id.id})
- self.bank_journal_euro = self.bank_euro.journal_id
+ self.bank_journal_euro = self.env['account.journal'].create({'name': 'Bank', 'type': 'bank', 'code': 'BNK67'})
self.account_euro = self.bank_journal_euro.default_debit_account_id
- self.bank_usd = self.env['res.partner.bank'].create({'acc_number': 'Reconciliation test USD',
- 'bank_name': 'Test Bank USD', 'company_id': self.env.user.company_id.id})
- self.bank_journal_usd = self.bank_usd.journal_id
+ self.bank_journal_usd = self.env['account.journal'].create({'name': 'Bank US', 'type': 'bank', 'code': 'BNK68', 'currency_id': self.currency_usd_id})
self.account_usd = self.bank_journal_usd.default_debit_account_id
- self.account_usd.write({'currency_id': self.currency_usd_id})
- self.bank_journal_usd.write({'currency_id': self.currency_usd_id})
+
self.diff_income_account = self.env['res.users'].browse(self.env.uid).company_id.income_currency_exchange_account_id
self.diff_expense_account = self.env['res.users'].browse(self.env.uid).company_id.expense_currency_exchange_account_id
diff --git a/addons/account/views/account_bank_view.xml b/addons/account/views/account_bank_view.xml
deleted file mode 100644
index d125251c360..00000000000
--- a/addons/account/views/account_bank_view.xml
+++ /dev/null
@@ -1,62 +0,0 @@
-
-
-
-
-
-
-
- Partner Bank Accounts - Journal
- res.partner.bank
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Partner Bank Accounts - Add currency on tree
- res.partner.bank
-
-
-
-
-
-
-
-
-
-
- Bank Accounts
- res.partner.bank
- form
- tree,form
-
-
-
- Click to setup a new bank account.
-
- Configure your company's bank account and select those that must
- appear on the report footer.
-
- If you use the accounting application of Odoo, journals and
- accounts will be created automatically based on these data.
-
-
diff --git a/addons/account_bank_statement_import/__init__.py b/addons/account_bank_statement_import/__init__.py
index a72befb7117..65797c0f6e3 100644
--- a/addons/account_bank_statement_import/__init__.py
+++ b/addons/account_bank_statement_import/__init__.py
@@ -1,5 +1,6 @@
# -*- encoding: utf-8 -*-
import account_bank_statement_import
+import account_journal
import wizard
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 c9ca9c19388..6ea8c4d266c 100644
--- a/addons/account_bank_statement_import/account_bank_statement_import.py
+++ b/addons/account_bank_statement_import/account_bank_statement_import.py
@@ -4,6 +4,7 @@ import base64
from openerp import api, fields, models, _
from openerp.exceptions import UserError
+from openerp.addons.base.res.res_bank import sanitize_account_number
import logging
_logger = logging.getLogger(__name__)
@@ -30,20 +31,17 @@ 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()
- #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
# 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))
+ currency_code, account_number, stmts_vals = self.with_context(active_id=self.ids[0])._parse_file(base64.b64decode(self.data_file))
# Check raw data
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)
+ currency, journal = 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)
+ return self.with_context(active_id=self.ids[0])._journal_creation_wizard(currency, account_number)
# Prepare statement data to be used for bank statements creation
stmts_vals = self._complete_stmts_vals(stmts_vals, journal, account_number)
# Create the bank statements
@@ -60,8 +58,8 @@ 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 """
+ def _journal_creation_wizard(self, currency, account_number):
+ """ Calls a wizard that allows the user to carry on with journal creation """
return {
'name': _('Journal Creation'),
'type': 'ir.actions.act_window',
@@ -71,10 +69,11 @@ class AccountBankStatementImport(models.TransientModel):
'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_bank_acc_number': account_number,
'default_name': _('Bank') + ' ' + account_number,
+ 'default_currency_id': currency and currency.id or False,
+ 'default_type': 'bank',
+ 'default_bank_statements_source': 'file_import',
}
}
@@ -118,10 +117,13 @@ class AccountBankStatementImport(models.TransientModel):
raise UserError(_('This file doesn\'t contain any transaction.'))
def _find_additional_data(self, currency_code, account_number):
- """ Get the res.currency ID and the res.partner.bank ID """
+ """ Look for a res.currency and account.journal using values extracted from the
+ statement and make sure it's consistent.
+ """
company_currency = self.env.user.company_id.currency_id
journal_obj = self.env['account.journal']
currency = None
+ sanitized_account_number = sanitize_account_number(account_number)
if currency_code:
currency = self.env['res.currency'].search([('name', '=ilike', currency_code)], limit=1)
@@ -130,31 +132,20 @@ class AccountBankStatementImport(models.TransientModel):
if currency == company_currency:
currency = False
- bank_account = None
- if account_number and len(account_number) > 4:
- bank_account = self.env['res.partner.bank'].search([('acc_number', '=', account_number)], limit=1)
+ journal = journal_obj.browse(self.env.context.get('journal_id', []))
+ if account_number:
+ # No bank account on the journal : create one from the account number of the statement
+ if journal and not journal.bank_account_id:
+ journal.set_bank_account(account_number)
+ # Already a bank account on the journal : check it's the same as on the statement
+ elif journal and journal.bank_account_id.sanitized_acc_number != sanitized_account_number:
+ raise UserError(_('The account of this statement (%s) is not the same as the journal (%s).') % (account_number, journal.bank_account_id.acc_number))
+ # No journal passed to the wizard : try to find one using the account number of the statement
+ elif not journal:
+ journal = journal_obj.search([('bank_account_id.sanitized_acc_number', '=', sanitized_account_number)])
- # Find the journal from context or bank account
- 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:
- bank_account.write({'journal_id': journal.id})
- else:
- if bank_account.journal_id:
- journal = bank_account.journal_id
-
- # If importing into an existing journal
+ # If importing into an existing journal, its currency must be the same as the bank statement
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))
-
- # Its currency must be the same as the bank statement
journal_currency = journal.currency_id
if currency == None:
currency = journal_currency
@@ -167,19 +158,7 @@ class AccountBankStatementImport(models.TransientModel):
if not journal and not account_number:
raise UserError(_('Cannot find in which journal import this statement. Please manually select a journal.'))
- 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('-', '')
- return self.env['res.partner.bank'].create({
- 'acc_number': account_number,
- 'state': bank_code,
- })
+ return currency, journal
def _complete_stmts_vals(self, stmts_vals, journal, account_number):
for st_vals in stmts_vals:
@@ -188,7 +167,8 @@ class AccountBankStatementImport(models.TransientModel):
for line_vals in st_vals['transactions']:
unique_import_id = line_vals.get('unique_import_id')
if unique_import_id:
- line_vals['unique_import_id'] = (account_number and account_number + '-' or '') + unique_import_id
+ sanitized_account_number = sanitize_account_number(account_number)
+ line_vals['unique_import_id'] = (sanitized_account_number and sanitized_account_number + '-' or '') + unique_import_id
if not line_vals.get('bank_account_id'):
# Find the partner and his bank account or create the bank account. The partner selected during the
@@ -202,9 +182,7 @@ class AccountBankStatementImport(models.TransientModel):
bank_account_id = partner_bank.id
partner_id = partner_bank.partner_id.id
else:
- #do not pass the journal_id in _create_bank_account() because we don't want to link
- #that bank_account to the journal (it belongs to a partner, not to the company)
- bank_account_id = self._create_bank_account(identifying_string).id
+ bank_account_id = self.env['res.partner.bank'].create({'acc_number': line_vals['account_number']}).id
line_vals['partner_id'] = partner_id
line_vals['bank_account_id'] = bank_account_id
@@ -221,7 +199,7 @@ class AccountBankStatementImport(models.TransientModel):
for st_vals in stmts_vals:
filtered_st_lines = []
for line_vals in st_vals['transactions']:
- if not 'unique_import_id' in line_vals \
+ if 'unique_import_id' not in line_vals \
or not line_vals['unique_import_id'] \
or not bool(BankStatementLine.sudo().search([('unique_import_id', '=', line_vals['unique_import_id'])], limit=1)):
filtered_st_lines.append(line_vals)
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
index ad708d30b63..d529f678028 100644
--- a/addons/account_bank_statement_import/account_bank_statement_import_view.xml
+++ b/addons/account_bank_statement_import/account_bank_statement_import_view.xml
@@ -30,4 +30,22 @@
+
+ account.journal.dashboard.kanban.inherit
+ account.journal
+
+
+
+
+
+
+
+
+
+
+ Import Statement
+
+
+
+
diff --git a/addons/account_bank_statement_import/account_journal.py b/addons/account_bank_statement_import/account_journal.py
new file mode 100644
index 00000000000..35267234bc6
--- /dev/null
+++ b/addons/account_bank_statement_import/account_journal.py
@@ -0,0 +1,21 @@
+# -*- coding: utf-8 -*-
+
+from openerp import models, fields, api
+
+class AccountJournal(models.Model):
+ _inherit = "account.journal"
+
+ bank_statements_source = fields.Selection(selection_add=[("file_import", "File Import")])
+
+ @api.multi
+ def import_statement(self):
+ """return action to import bank/cash statements. This button should be called only on journals with type =='bank'"""
+ self.bank_statements_source = 'file_import'
+ model = 'account.bank.statement'
+ 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.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/demo/partner_bank.xml b/addons/account_bank_statement_import/demo/partner_bank.xml
index 47e8fa76f48..09c14d42308 100644
--- a/addons/account_bank_statement_import/demo/partner_bank.xml
+++ b/addons/account_bank_statement_import/demo/partner_bank.xml
@@ -3,35 +3,31 @@
- Agrolait00987654321
- bank
-
+ bank
+
- China Export00987654322
- bank
-
+ bank
+
- Delta PC10987654320
- bank
-
+ bank
+
- Epic Technologies10987654322
- bank
-
+ bank
+
diff --git a/addons/account_bank_statement_import/wizard/journal_creation.py b/addons/account_bank_statement_import/wizard/journal_creation.py
index 3acd180ac50..82417ecb661 100644
--- a/addons/account_bank_statement_import/wizard/journal_creation.py
+++ b/addons/account_bank_statement_import/wizard/journal_creation.py
@@ -6,37 +6,10 @@ class account_bank_statement_import_journal_creation(models.TransientModel):
_name = 'account.bank.statement.import.journal.creation'
_description = 'Import Bank Statement Journal Creation Wizard'
- name = fields.Char('Journal Name', required=True)
- currency_id = fields.Many2one('res.currency', 'Currency', readonly=True)
- account_number = fields.Char('Account Number', readonly=True)
+ journal_id = fields.Many2one('account.journal', delegate=True, required=True, ondelete='cascade')
@api.multi
def create_journal(self):
- import_wiz_obj = self.env['account.bank.statement.import']
- journal_obj = self.env['account.journal']
- company = self.env.user.company_id
- wiz = self[0]
- currency_id = wiz.currency_id.id
- account_number = wiz.account_number
-
- 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)
- journal = journal_obj.create(vals_journal)
- self.env['res.partner.bank'].browse(bank_account_id).write({'journal_id': journal.id})
- else:
- #create the bank account that will trigger the journal and account.account creation
- res_partner_bank_vals = {
- 'acc_number': account_number,
- 'currency_id': currency_id,
- 'company_id': company.id,
- 'owner_name': company.partner_id.name,
- 'partner_id': company.partner_id.id,
- 'footer': True
- }
- 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'])
- return statement_import_transient.import_file()
+ """ Create the journal (the record is automatically created in the process of calling this method) and reprocess the statement """
+ statement_import_transient = self.env['account.bank.statement.import'].browse(self.env.context['statement_import_transient_id'])
+ return statement_import_transient.with_context(journal_id=self.journal_id.id).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 e64b6db7a60..10c29546bf8 100644
--- a/addons/account_bank_statement_import/wizard/journal_creation.xml
+++ b/addons/account_bank_statement_import/wizard/journal_creation.xml
@@ -7,12 +7,18 @@
account.bank.statement.import.journal.creation
-
+
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
@@ -86,7 +68,7 @@
-
+
diff --git a/openerp/addons/base/res/res_partner_data.xml b/openerp/addons/base/res/res_partner_data.xml
index 841a66d316d..607b149c2ed 100644
--- a/openerp/addons/base/res/res_partner_data.xml
+++ b/openerp/addons/base/res/res_partner_data.xml
@@ -30,17 +30,6 @@
Prof.
-
-
- Normal Bank Account
- bank
-
-
-
- bank_bic
-
-
-
diff --git a/openerp/addons/base/security/ir.model.access.csv b/openerp/addons/base/security/ir.model.access.csv
index 1dcfeb81c9c..1357acc31ac 100644
--- a/openerp/addons/base/security/ir.model.access.csv
+++ b/openerp/addons/base/security/ir.model.access.csv
@@ -63,10 +63,6 @@
"access_res_partner_group_user","res_partner group_user","model_res_partner","group_user",1,0,0,0
"access_res_partner_bank_group_user","res_partner_bank group_user","model_res_partner_bank","group_user",1,0,0,0
"access_res_partner_bank_group_partner_manager","res_partner_bank group_partner_manager","model_res_partner_bank","group_partner_manager",1,1,1,1
-"access_res_partner_bank_type_group_partner_manager","res_partner_bank_type group_partner_manager","model_res_partner_bank_type","group_partner_manager",1,1,1,1
-"access_res_partner_bank_type_group_user","res_partner_bank_type group_user","model_res_partner_bank_type",,1,0,0,0
-"access_res_partner_bank_type_field_group_partner_manager","res_partner_bank_type_field group_partner_manager","model_res_partner_bank_type_field","group_partner_manager",1,1,1,1
-"access_res_partner_bank_type_field_group_user","res_partner_bank_type_field group_user","model_res_partner_bank_type_field",,1,0,0,0
"access_res_partner_category_group_user","res_partner_category group_user","model_res_partner_category","group_user",1,0,0,0
"access_res_partner_category_group_partner_manager","res_partner_category group_partner_manager","model_res_partner_category","group_partner_manager",1,1,1,1
"access_res_partner_title_group_user","res_partner_title group_user","model_res_partner_title","group_partner_manager",1,1,1,1
diff --git a/openerp/addons/base/tests/__init__.py b/openerp/addons/base/tests/__init__.py
index 82b79cfc693..d58e4931ec7 100644
--- a/openerp/addons/base/tests/__init__.py
+++ b/openerp/addons/base/tests/__init__.py
@@ -25,3 +25,4 @@ import test_translate
import test_view_validation
import test_views
import test_xmlrpc
+import test_res_partner_bank
diff --git a/openerp/addons/base/tests/test_expression.py b/openerp/addons/base/tests/test_expression.py
index a3a93971b59..9bf61d61473 100644
--- a/openerp/addons/base/tests/test_expression.py
+++ b/openerp/addons/base/tests/test_expression.py
@@ -175,8 +175,6 @@ class test_expression(common.TransactionCase):
partner_bank_ids_col = partner_obj._columns.get('bank_ids') # one2many on res.partner to res.partner.bank
category_id_col = partner_obj._columns.get('category_id') # many2many on res.partner to res.partner.category
- # Get the first bank account type to be able to create a res.partner.bank
- bank_type = bank_obj._bank_type_get(cr, uid)[0]
# Get country/state data
country_us_id = registry('res.country').search(cr, uid, [('code', 'like', 'US')])[0]
state_ids = registry('res.country.state').search(cr, uid, [('country_id', '=', country_us_id)], limit=2)
@@ -187,9 +185,9 @@ class test_expression(common.TransactionCase):
p_aa = partner_obj.create(cr, uid, {'name': 'test__AA', 'parent_id': p_a, 'state_id': state_ids[0]})
p_ab = partner_obj.create(cr, uid, {'name': 'test__AB', 'parent_id': p_a, 'state_id': state_ids[1]})
p_ba = partner_obj.create(cr, uid, {'name': 'test__BA', 'parent_id': p_b, 'state_id': state_ids[0]})
- b_aa = bank_obj.create(cr, uid, {'acc_number': '__bank_test_a', 'state': bank_type[0], 'partner_id': p_aa})
- b_ab = bank_obj.create(cr, uid, {'acc_number': '__bank_test_b', 'state': bank_type[0], 'partner_id': p_ab})
- b_ba = bank_obj.create(cr, uid, {'acc_number': '__bank_test_b', 'state': bank_type[0], 'partner_id': p_ba})
+ b_aa = bank_obj.create(cr, uid, {'acc_number': '123', 'acc_type': 'bank', 'partner_id': p_aa})
+ b_ab = bank_obj.create(cr, uid, {'acc_number': '456', 'acc_type': 'bank', 'partner_id': p_ab})
+ b_ba = bank_obj.create(cr, uid, {'acc_number': '789', 'acc_type': 'bank', 'partner_id': p_ba})
# --------------------------------------------------
# Test1: basics about the attribute
@@ -203,34 +201,34 @@ class test_expression(common.TransactionCase):
# Test2: one2many
# --------------------------------------------------
- name_test = 'test_a'
+ name_test = '12'
# Do: one2many without _auto_join
self._reinit_mock()
- partner_ids = partner_obj.search(cr, uid, [('bank_ids.acc_number', 'like', name_test)])
+ partner_ids = partner_obj.search(cr, uid, [('bank_ids.sanitized_acc_number', 'like', name_test)])
# Test result
self.assertEqual(set(partner_ids), set([p_aa]),
- "_auto_join off: ('bank_ids.acc_number', 'like', '..'): incorrect result")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..'): incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 3,
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') should produce 3 queries (1 in res_partner_bank, 2 on res_partner)")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') should produce 3 queries (1 in res_partner_bank, 2 on res_partner)")
sql_query = self.query_list[0].get_sql()
self.assertIn('res_partner_bank', sql_query[0],
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') first query incorrect main table")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect main table")
- expected = "%s::text like %s" % (unaccent('"res_partner_bank"."acc_number"'), unaccent('%s'))
+ expected = "%s::text like %s" % (unaccent('"res_partner_bank"."sanitized_acc_number"'), unaccent('%s'))
self.assertIn(expected, sql_query[1],
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') first query incorrect where condition")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect where condition")
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') first query incorrect parameter")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') first query incorrect parameter")
sql_query = self.query_list[2].get_sql()
self.assertIn('res_partner', sql_query[0],
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') third query incorrect main table")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') third query incorrect main table")
self.assertIn('"res_partner"."id" in (%s)', sql_query[1],
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') third query incorrect where condition")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') third query incorrect where condition")
self.assertEqual(set([p_aa]), set(sql_query[2]),
- "_auto_join off: ('bank_ids.acc_number', 'like', '..') third query incorrect parameter")
+ "_auto_join off: ('bank_ids.sanitized_acc_number', 'like', '..') third query incorrect parameter")
# Do: cascaded one2many without _auto_join
self._reinit_mock()
@@ -245,27 +243,27 @@ class test_expression(common.TransactionCase):
# Do: one2many with _auto_join
partner_bank_ids_col._auto_join = True
self._reinit_mock()
- partner_ids = partner_obj.search(cr, uid, [('bank_ids.acc_number', 'like', 'test_a')])
+ partner_ids = partner_obj.search(cr, uid, [('bank_ids.sanitized_acc_number', 'like', '12')])
# Test result
self.assertEqual(set(partner_ids), set([p_aa]),
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') incorrect result")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') incorrect result")
# Test produced queries
self.assertEqual(len(self.query_list), 1,
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') should produce 1 query")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') should produce 1 query")
sql_query = self.query_list[0].get_sql()
self.assertIn('"res_partner"', sql_query[0],
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect main table")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect main table")
self.assertIn('"res_partner_bank" as "res_partner__bank_ids"', sql_query[0],
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect join")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect join")
- expected = "%s::text like %s" % (unaccent('"res_partner__bank_ids"."acc_number"'), unaccent('%s'))
+ expected = "%s::text like %s" % (unaccent('"res_partner__bank_ids"."sanitized_acc_number"'), unaccent('%s'))
self.assertIn(expected, sql_query[1],
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect where condition")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect where condition")
self.assertIn('"res_partner"."id"="res_partner__bank_ids"."partner_id"', sql_query[1],
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect join condition")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect join condition")
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
- "_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect parameter")
+ "_auto_join on: ('bank_ids.sanitized_acc_number', 'like', '..') query incorrect parameter")
# Do: one2many with _auto_join, test final leaf is an id
self._reinit_mock()
@@ -426,7 +424,7 @@ class test_expression(common.TransactionCase):
partner_child_ids_col._auto_join = True
partner_bank_ids_col._auto_join = True
partner_child_ids_col._domain = lambda self: ['!', ('name', '=', self._name)]
- partner_bank_ids_col._domain = [('acc_number', 'like', 'a')]
+ partner_bank_ids_col._domain = [('sanitized_acc_number', 'like', '2')]
# Do: 2 cascaded one2many with _auto_join, test final leaf is an id
self._reinit_mock()
partner_ids = partner_obj.search(cr, uid, ['&', (1, '=', 1), ('child_ids.bank_ids.id', 'in', [b_aa, b_ba])])
@@ -438,7 +436,7 @@ class test_expression(common.TransactionCase):
# Test produced queries that domains effectively present
sql_query = self.query_list[0].get_sql()
- expected = "%s::text like %s" % (unaccent('"res_partner__child_ids__bank_ids"."acc_number"'), unaccent('%s'))
+ expected = "%s::text like %s" % (unaccent('"res_partner__child_ids__bank_ids"."sanitized_acc_number"'), unaccent('%s'))
self.assertIn(expected, sql_query[1],
"_auto_join on one2many with domains incorrect result")
# TDE TODO: check first domain has a correct table name
diff --git a/openerp/addons/base/tests/test_osv_expression.yml b/openerp/addons/base/tests/test_osv_expression.yml
index 3a917528474..813acfd2669 100644
--- a/openerp/addons/base/tests/test_osv_expression.yml
+++ b/openerp/addons/base/tests/test_osv_expression.yml
@@ -206,7 +206,7 @@
# that don't have OpenERP has a parent company, you expect to find,
# among others, the companies that don't have parent company.
#
-
+
# existing values be treated similarly if we simply check that some
# existing value belongs to them.
@@ -367,52 +367,14 @@
Equivalent queries, one2many.
-
!python {model: res.company }: |
- # Search the company via its one2many (the one2many must point back at the company).
company = self.browse(cr, uid, ref('ymltest_company3'))
- max_currency_id = max(self.pool['res.partner.bank'].search(cr, uid, []))
- bank_ids1 = self.pool['res.partner.bank'].search(cr, uid, [('acc_number', 'not like', 'probably_unexisting_name')])
- bank_ids2 = self.pool['res.partner.bank'].search(cr, uid, [('id', 'not in', [max_currency_id + 1003])])
- bank_ids3 = self.pool['res.partner.bank'].search(cr, uid, [('id', 'not in', [])])
- assert bank_ids1 == bank_ids2 == bank_ids3, 'All 3 results should have be the same: all banks'
- default_company = self.browse(cr, uid, 1)
- # set manually a bank to the default company.
- self.pool['res.partner.bank'].write(cr, uid, bank_ids1, {'company_id': default_company.id})
# one2many towards same model
res_1 = self.search(cr, uid, [('child_ids', 'in', [x.id for x in company.child_ids])]) # any company having a child of company3 as child
res_2 = self.search(cr, uid, [('child_ids', 'in', [company.child_ids[0].id])]) # any company having the first child of company3 as child
- # one2many towards another model
- res_3 = self.search(cr, uid, [('bank_ids', 'in', [x.id for x in default_company.bank_ids])]) # companies having a currency of main company
- res_4 = self.search(cr, uid, [('bank_ids', 'in', [default_company.bank_ids[0].id])]) # companies having first currency of main company
- res_5 = self.search(cr, uid, [('bank_ids', 'in', default_company.bank_ids[0].id)]) # companies having first currency of main company
- # res_6 = self.search(cr, uid, [('bank_ids', 'in', [default_company.currency_ids[0].name])]) # TODO
- res_7 = self.search(cr, uid, [('bank_ids', '=', default_company.bank_ids[0].acc_number)])
- res_8 = self.search(cr, uid, [('bank_ids', 'like', default_company.bank_ids[0].acc_number)])
-
- res_9 = self.search(cr, uid, [('bank_ids', 'like', 'probably_unexisting_name')])
- # self.search(cr, uid, [('bank_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception
assert res_1 == [ref('ymltest_company3')], "res_1"
assert res_2 == [ref('ymltest_company3')], "res_2"
- assert res_3 == [1], "res_3"
- assert res_4 == [1], "res_4"
- assert res_5 == [1], "res_5"
- assert res_7 == [1], "res_7"
- assert res_8 == [1], "res_8"
- assert res_9 == [], "res_9"
- # get the companies referenced by some currency (this is normally the main company) using a weird negative domain
- res_10 = self.search(cr, uid, [('bank_ids', 'not like', 'probably_unexisting_name')])
- res_11 = self.search(cr, uid, [('bank_ids', 'not in', [max_currency_id + 1])])
- res_12 = self.search(cr, uid, [('bank_ids', '!=', False)])
- res_13 = self.search(cr, uid, [('bank_ids', 'not in', [])])
- res_10.sort()
- res_11.sort()
- res_12.sort()
- res_13.sort()
- assert res_10 == res_11
- assert res_10 == res_12
- assert res_10 == res_13
-
# try testing real subsets with IN/NOT IN
res_partner = self.pool.get('res.partner')
res_users = self.pool.get('res.users')
@@ -443,6 +405,53 @@
assert res_2 == expected
assert res_3 == expected
assert res_4 == expected
+-
+ Equivalent queries, one2many.
+-
+ !python {model: res.currency }: |
+ # Create a currency and a currency rate
+ res_currency = self.pool['res.currency']
+ res_currency_rate = self.pool['res.currency.rate']
+ currency = res_currency.create(cr, uid, {'name': 'ZZZ', 'symbol': 'ZZZ', 'rounding': 1.0})
+ currency_rate = self.pool['res.currency.rate'].create(cr, uid, {'name': '2010-01-01', 'currency_id': currency, 'rate': 1.0})
+
+ # Search the currency via its rates one2many (the one2many must point back at the currency).
+ max_currency_rate_id = max(res_currency_rate.search(cr, uid, []))
+ currency_rate1 = res_currency_rate.search(cr, uid, [('name', 'not like', 'probably_unexisting_name')])
+ currency_rate2 = res_currency_rate.search(cr, uid, [('id', 'not in', [max_currency_rate_id + 1003])])
+ currency_rate3 = res_currency_rate.search(cr, uid, [('id', 'not in', [])])
+ assert currency_rate1 == currency_rate2 == currency_rate3, 'All 3 results should be the same : empty'
+ default_currency = self.browse(cr, uid, 1)
+
+ # one2many towards another model
+ res_3 = self.search(cr, uid, [('rate_ids', 'in', [x.id for x in default_currency.rate_ids])]) # currencies having a rate of main currency
+ res_4 = self.search(cr, uid, [('rate_ids', 'in', [default_currency.rate_ids[0].id])]) # currencies having first rate of main currency
+ res_5 = self.search(cr, uid, [('rate_ids', 'in', default_currency.rate_ids[0].id)]) # currencies having first rate of main currency
+ # res_6 = self.search(cr, uid, [('rate_ids', 'in', [default_currency.rate_ids[0].name])])
+ # res_7 = self.search(cr, uid, [('rate_ids', '=', default_currency.rate_ids[0].name)])
+ # res_8 = self.search(cr, uid, [('rate_ids', 'like', default_currency.rate_ids[0].name)])
+
+ res_9 = self.search(cr, uid, [('rate_ids', 'like', 'probably_unexisting_name')])
+ # self.search(cr, uid, [('rate_ids', 'unexisting_op', 'probably_unexisting_name')]) # TODO expected exception
+ assert res_3 == [1], "res_3"
+ assert res_4 == [1], "res_4"
+ assert res_5 == [1], "res_5"
+ # assert res_7 == [1], "res_7"
+ # assert res_8 == [1], "res_8"
+ assert res_9 == [], "res_9"
+
+ # get the currencies referenced by some currency rates using a weird negative domain
+ res_10 = self.search(cr, uid, [('rate_ids', 'not like', 'probably_unexisting_name')])
+ res_11 = self.search(cr, uid, [('rate_ids', 'not in', [max_currency_rate_id + 1])])
+ res_12 = self.search(cr, uid, [('rate_ids', '!=', False)])
+ res_13 = self.search(cr, uid, [('rate_ids', 'not in', [])])
+ res_10.sort()
+ res_11.sort()
+ res_12.sort()
+ res_13.sort()
+ assert res_10 == res_11, 'res_11'
+ assert res_10 == res_12, 'res_12'
+ assert res_10 == res_13, 'res_13'
-
Unaccent. Create a company with an accent in its name.
-
diff --git a/openerp/addons/base/tests/test_res_partner_bank.py b/openerp/addons/base/tests/test_res_partner_bank.py
new file mode 100644
index 00000000000..40cd9f797bf
--- /dev/null
+++ b/openerp/addons/base/tests/test_res_partner_bank.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+##############################################################################
+#
+# This file is part of account_bank_statement_import,
+# an Odoo module.
+#
+# Copyright (c) 2015 ACSONE SA/NV ()
+#
+# account_bank_statement_import 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.
+#
+# account_bank_statement_import 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 account_bank_statement_import_coda.
+# If not, see .
+#
+##############################################################################
+from openerp.tests.common import TransactionCase
+
+
+class TestResPartnerBank(TransactionCase):
+ """Tests acc_number
+ """
+
+ def test_sanitized_acc_number(self):
+ partner_bank_model = self.env['res.partner.bank']
+ acc_number = " BE-001 2518823 03 "
+ vals = partner_bank_model.search([('acc_number', '=', acc_number)])
+ self.assertEquals(0, len(vals))
+ partner_bank = partner_bank_model.create({
+ 'acc_number': acc_number,
+ 'partner_id': self.ref('base.res_partner_2'),
+ 'acc_type': 'bank',
+ })
+ vals = partner_bank_model.search([('acc_number', '=', acc_number)])
+ self.assertEquals(1, len(vals))
+ self.assertEquals(partner_bank, vals[0])
+ vals = partner_bank_model.search([('acc_number', 'in', [acc_number])])
+ self.assertEquals(1, len(vals))
+ self.assertEquals(partner_bank, vals[0])
+
+ self.assertEqual(partner_bank.acc_number, acc_number)
+
+ # sanitaze the acc_number
+ sanitized_acc_number = 'BE001251882303'
+ vals = partner_bank_model.search(
+ [('acc_number', '=', sanitized_acc_number)])
+ self.assertEquals(1, len(vals))
+ self.assertEquals(partner_bank, vals[0])
+ vals = partner_bank_model.search(
+ [('acc_number', 'in', [sanitized_acc_number])])
+ self.assertEquals(1, len(vals))
+ self.assertEquals(partner_bank, vals[0])
+ self.assertEqual(partner_bank.sanitized_acc_number,
+ sanitized_acc_number)
+
+ # search is case insensitive
+ vals = partner_bank_model.search(
+ [('acc_number', '=', sanitized_acc_number.lower())])
+ self.assertEquals(1, len(vals))
+ vals = partner_bank_model.search(
+ [('acc_number', '=', acc_number.lower())])
+ self.assertEquals(1, len(vals))