[REF] account, base: refactoring/improvements/fixes of bank accounts and payments
This commit is contained in:
committed by
Quentin De Paoli
parent
98b78da223
commit
b8759cc348
@@ -299,8 +299,84 @@ class AccountJournal(models.Model):
|
||||
seq['company_id'] = vals['company_id']
|
||||
return self.env['ir.sequence'].create(seq)
|
||||
|
||||
@api.model
|
||||
def _prepare_bank_account(self, name, company, currency_id):
|
||||
'''
|
||||
This function prepares the value to use for the creation of the default debit and credit accounts of a
|
||||
bank journal (created through the wizard of generating COA from templates for example).
|
||||
|
||||
:param name: name of the bank account
|
||||
:param company: company for which the wizard is running
|
||||
:param currency_id: ID of the currency in wich is the bank account
|
||||
:return: mapping of field names and values
|
||||
:rtype: dict
|
||||
'''
|
||||
|
||||
# Seek the next available number for the account code
|
||||
code_digits = company.accounts_code_digits or 0
|
||||
bank_account_code_char = company.bank_account_code_char or ''
|
||||
for num in xrange(1, 100):
|
||||
new_code = str(bank_account_code_char.ljust(code_digits - 1, '0')) + str(num)
|
||||
rec = self.env['account.account'].search([('code', '=', new_code), ('company_id', '=', company.id)], limit=1)
|
||||
if not rec:
|
||||
break
|
||||
else:
|
||||
raise UserError(_('Cannot generate an unused account code.'))
|
||||
|
||||
liquidity_type = self.env.ref('account.data_account_type_liquidity')
|
||||
return {
|
||||
'name': name,
|
||||
'currency_id': currency_id or False,
|
||||
'code': new_code,
|
||||
'user_type': liquidity_type and liquidity_type.id or False,
|
||||
'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):
|
||||
if vals.get('type') in ('bank', 'cash'):
|
||||
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'])
|
||||
account_vals = self._prepare_bank_account(vals.get('name'), company, vals.get('currency_id'))
|
||||
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})
|
||||
@@ -555,4 +631,4 @@ class AccountOperationTemplate(models.Model):
|
||||
|
||||
@api.onchange('name')
|
||||
def onchange_name(self):
|
||||
self.label = self.name
|
||||
self.label = self.name
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp import api, fields, models, _
|
||||
from openerp import api, fields, models
|
||||
|
||||
|
||||
class Bank(models.Model):
|
||||
@@ -8,8 +8,6 @@ class Bank(models.Model):
|
||||
|
||||
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")
|
||||
currency_id = fields.Many2one('res.currency', related='journal_id.currency_id', string='Currency',
|
||||
readonly=True, help="Currency of the related account journal.")
|
||||
|
||||
@api.model
|
||||
def create(self, data):
|
||||
@@ -26,70 +24,21 @@ class Bank(models.Model):
|
||||
@api.model
|
||||
def _prepare_name(self, bank):
|
||||
"Return the name to use when creating a bank journal"
|
||||
return (bank.bank_name or '') + ' ' + (bank.acc_number or '')
|
||||
|
||||
@api.model
|
||||
def _prepare_name_get(self, bank_dicts):
|
||||
"""Add ability to have %(currency_name)s in the format_layout of res.partner.bank.type"""
|
||||
currency_ids = list(set(data['currency_id'][0] for data in bank_dicts if data.get('currency_id')))
|
||||
currencies = self.env['res.currency'].browse(currency_ids)
|
||||
currency_name = dict((currency.id, currency.name) for currency in currencies)
|
||||
|
||||
for data in bank_dicts:
|
||||
data['currency_name'] = data.get('currency_id') and currency_name[data['currency_id'][0]] or ''
|
||||
return super(Bank, self)._prepare_name_get(bank_dicts)
|
||||
name = bank.bank_name + ' ' if bank.bank_name else ''
|
||||
name += bank.acc_number
|
||||
return name
|
||||
|
||||
@api.multi
|
||||
def post_write(self):
|
||||
AccountObj = self.env['account.account']
|
||||
JournalObj = self.env['account.journal']
|
||||
|
||||
for bank in self:
|
||||
# Create a journal for the bank account if it belongs to the company.
|
||||
if bank.partner_id in self.env.user.company_ids.mapped('partner_id') and not bank.journal_id:
|
||||
# TODO: this code is duplicated; refactor using _prepare_bank_account() in chart_template.py
|
||||
# Find the code and parent of the bank account to create
|
||||
dig = 6
|
||||
current_num = 1
|
||||
account = AccountObj.search([('internal_type', '=', 'liquidity'), ('company_id', '=', bank.company_id.id)], limit=1)
|
||||
# No liquidity account exists, no template available
|
||||
if not account: continue
|
||||
|
||||
ref_acc_bank = account
|
||||
while True:
|
||||
new_code = str(ref_acc_bank.code.ljust(dig-len(str(current_num)), '0')) + str(current_num)
|
||||
account = AccountObj.search([('code', '=', new_code), ('company_id', '=', bank.company_id.id)], limit=1)
|
||||
if not account:
|
||||
break
|
||||
current_num += 1
|
||||
name = self._prepare_name(bank)
|
||||
acc = {
|
||||
'name': name,
|
||||
'code': new_code,
|
||||
'user_type': ref_acc_bank.user_type.id,
|
||||
'reconcile': False,
|
||||
'company_id': bank.company_id.id,
|
||||
}
|
||||
acc_bank = AccountObj.create(acc)
|
||||
|
||||
new_code = 1
|
||||
while True:
|
||||
code = _('BNK')+str(new_code)
|
||||
account = JournalObj.search([('code', '=', code)], limit=1)
|
||||
if not account:
|
||||
break
|
||||
new_code += 1
|
||||
|
||||
#create the bank journal
|
||||
vals_journal = {
|
||||
'name': name,
|
||||
'code': code,
|
||||
'type': 'bank',
|
||||
'company_id': bank.company_id.id,
|
||||
'analytic_journal_id': False,
|
||||
'default_credit_account_id': acc_bank.id,
|
||||
'default_debit_account_id': acc_bank.id,
|
||||
}
|
||||
|
||||
bank.journal_id = JournalObj.create(vals_journal)
|
||||
return True
|
||||
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)
|
||||
|
||||
@@ -32,6 +32,8 @@ class account_abstract_payment(models.AbstractModel):
|
||||
|
||||
payment_type = fields.Selection([('outbound', 'Send Money'), ('inbound', 'Receive Money')], default='outbound', required=True)
|
||||
payment_method = fields.Many2one('account.payment.method', string='Payment Method', required=True)
|
||||
payment_method_code = fields.Char(related='payment_method.code',
|
||||
help="Technical field used to adapt the interface to the payment method selected.")
|
||||
|
||||
partner_type = fields.Selection([('customer', 'Customer'), ('supplier', 'Supplier')], default='supplier')
|
||||
partner_id = fields.Many2one('res.partner', string='Partner')
|
||||
@@ -52,18 +54,6 @@ class account_abstract_payment(models.AbstractModel):
|
||||
if not self.amount > 0.0:
|
||||
raise ValidationError('The payment amount must be strictly positive.')
|
||||
|
||||
@api.one
|
||||
@api.constrains('communication')
|
||||
def _check_communication(self):
|
||||
""" This method is to be overwritten by payment type modules. The method body would look like :
|
||||
if self.payment_method == self.env.ref('my_module.payment_method'):
|
||||
try:
|
||||
self.communication.decode('ascii')
|
||||
except UnicodeDecodeError:
|
||||
raise ValidationError(_t("The communication cannot contain any special character"))
|
||||
"""
|
||||
pass
|
||||
|
||||
@api.one
|
||||
@api.depends('payment_type', 'journal_id')
|
||||
def _compute_hide_payment_method(self):
|
||||
@@ -272,6 +262,21 @@ class account_payment(models.Model):
|
||||
def _get_invoices(self):
|
||||
return self.invoice_ids
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
self._check_communication(vals['payment_method'], vals.get('communication', ''))
|
||||
return super(account_payment, self).create(vals)
|
||||
|
||||
def _check_communication(self, payment_method_id, communication):
|
||||
""" This method is to be overwritten by payment type modules. The method body would look like :
|
||||
if payment_method_id == self.env.ref('my_module.payment_method').id:
|
||||
try:
|
||||
communication.decode('ascii')
|
||||
except UnicodeError:
|
||||
raise ValidationError(_("The communication cannot contain any special character"))
|
||||
"""
|
||||
pass
|
||||
|
||||
@api.multi
|
||||
def button_journal_entries(self):
|
||||
return {
|
||||
|
||||
@@ -50,55 +50,6 @@ class AccountAccountTemplate(models.Model):
|
||||
return res
|
||||
|
||||
|
||||
class AccountAddTmplWizard(models.TransientModel):
|
||||
"""Add one more account from the template.
|
||||
|
||||
With the 'nocreate' option, some accounts may not be created. Use this to add them later."""
|
||||
_name = 'account.addtmpl.wizard'
|
||||
|
||||
@api.model
|
||||
def _get_def_cparent(self):
|
||||
context = self._context or {}
|
||||
tmpl_obj = self.env['account.account.template']
|
||||
|
||||
tids = tmpl_obj.read([context['tmpl_ids']], ['parent_id'])
|
||||
if not tids or not tids[0]['parent_id']:
|
||||
return False
|
||||
ptids = tmpl_obj.read([tids[0]['parent_id'][0]], ['code'])
|
||||
account = False
|
||||
if not ptids or not ptids[0]['code']:
|
||||
raise UserError(_('There is no parent code for the template account.'))
|
||||
account = self.env['account.account'].search([('code', '=', ptids[0]['code'])], limit=1)
|
||||
return account
|
||||
|
||||
cparent_id = fields.Many2one('account.account', string='Parent target', default=lambda self: self._get_def_cparent(),
|
||||
help="Creates an account with the selected template under this existing parent.", required=True, domain=[('deprecated', '=', False)])
|
||||
|
||||
@api.multi
|
||||
def action_create(self):
|
||||
context = self._context or {}
|
||||
AccountObj = self.env['account.account']
|
||||
data = self.read()[0]
|
||||
company_id = AccountObj.read([data['cparent_id'][0]], ['company_id'])[0]['company_id'][0]
|
||||
account_template = self.env['account.account.template'].browse(context['tmpl_ids'])
|
||||
vals = {
|
||||
'name': account_template.name,
|
||||
'currency_id': account_template.currency_id and account_template.currency_id.id or False,
|
||||
'code': account_template.code,
|
||||
'user_type': account_template.user_type and account_template.user_type.id or False,
|
||||
'reconcile': account_template.reconcile,
|
||||
'note': account_template.note,
|
||||
'parent_id': data['cparent_id'][0],
|
||||
'company_id': company_id,
|
||||
}
|
||||
AccountObj.create(vals)
|
||||
return {'type': 'state', 'state': 'end'}
|
||||
|
||||
@api.multi
|
||||
def action_cancel(self):
|
||||
return {'type': 'state', 'state': 'end'}
|
||||
|
||||
|
||||
class AccountChartTemplate(models.Model):
|
||||
_name = "account.chart.template"
|
||||
_description = "Templates for Account Chart"
|
||||
@@ -776,74 +727,6 @@ class WizardMultiChartsAccounts(models.TransientModel):
|
||||
self._create_bank_journals_from_o2m(company, acc_template_ref)
|
||||
return {}
|
||||
|
||||
@api.model
|
||||
def _prepare_bank_journal(self, company, line, default_account_id):
|
||||
'''
|
||||
This function prepares the value to use for the creation of a bank journal created through the wizard of
|
||||
generating COA from templates.
|
||||
|
||||
:param line: dictionary containing the values encoded by the user related to his bank account
|
||||
:param default_account_id: id of the default debit.credit account created before for this journal.
|
||||
:param company_id: id of the company for which the wizard is running
|
||||
: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['account_type'] == '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['account_type'],
|
||||
'company_id': company.id,
|
||||
'analytic_journal_id': False,
|
||||
'currency_id': line['currency_id'] or False,
|
||||
'default_credit_account_id': default_account_id,
|
||||
'default_debit_account_id': default_account_id,
|
||||
'show_on_dashboard': True,
|
||||
}
|
||||
|
||||
@api.model
|
||||
def _prepare_bank_account(self, company, line):
|
||||
'''
|
||||
This function prepares the value to use for the creation of the default debit and credit accounts 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
|
||||
:return: mapping of field names and values
|
||||
:rtype: dict
|
||||
'''
|
||||
|
||||
# Seek the next available number for the account code
|
||||
code_digits = company.accounts_code_digits or 0
|
||||
bank_account_code_char = company.bank_account_code_char or ''
|
||||
for num in xrange(1, 100):
|
||||
new_code = str(bank_account_code_char.ljust(code_digits - 1, '0')) + str(num)
|
||||
rec = self.env['account.account'].search([('code', '=', new_code), ('company_id', '=', company.id)], limit=1)
|
||||
if not rec:
|
||||
break
|
||||
else:
|
||||
raise UserError(_('Cannot generate an unused account code.'))
|
||||
|
||||
liquidity_type = self.env.ref('account.data_account_type_liquidity')
|
||||
|
||||
return {
|
||||
'name': line['acc_name'],
|
||||
'currency_id': line['currency_id'] or False,
|
||||
'code': new_code,
|
||||
'user_type': liquidity_type and liquidity_type.id or False,
|
||||
'company_id': company.id,
|
||||
}
|
||||
|
||||
@api.multi
|
||||
def _create_bank_journals_from_o2m(self, company, acc_template_ref):
|
||||
'''
|
||||
@@ -872,13 +755,21 @@ class WizardMultiChartsAccounts(models.TransientModel):
|
||||
company.write({'bank_account_code_char': ref_acc_bank})
|
||||
|
||||
for line in journal_data:
|
||||
# Create the default debit/credit accounts for this bank journal
|
||||
vals = self._prepare_bank_account(company, line)
|
||||
default_account = self.env['account.account'].create(vals)
|
||||
|
||||
#create the bank journal
|
||||
vals_journal = self._prepare_bank_journal(company, line, default_account.id)
|
||||
self.env['account.journal'].create(vals_journal)
|
||||
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
|
||||
|
||||
|
||||
@@ -889,4 +780,4 @@ class AccountBankAccountsWizard(models.TransientModel):
|
||||
bank_account_id = fields.Many2one('wizard.multi.charts.accounts', string='Bank Account', required=True, ondelete='cascade')
|
||||
currency_id = fields.Many2one('res.currency', string='Secondary Currency',
|
||||
help="Forces all moves for this account to have this secondary currency.")
|
||||
account_type = fields.Selection([('cash', 'Cash'), ('bank', 'Bank')])
|
||||
account_type = fields.Selection([('cash', 'Cash'), ('bank', 'Bank')])
|
||||
|
||||
@@ -32,22 +32,6 @@ class ResCompany(models.Model):
|
||||
string="Loss Exchange Rate Account", domain="[('internal_type', '=', 'other'), ('deprecated', '=', False), ('company_id', '=', id)]")
|
||||
anglo_saxon_accounting = fields.Boolean(string="Use anglo-saxon accounting")
|
||||
|
||||
@api.multi
|
||||
def _create_bank_account_and_journal(self, account_number, currency_id=None):
|
||||
""" Create a journal and its account """
|
||||
MultiChartsAccounts = self.env['wizard.multi.charts.accounts']
|
||||
|
||||
if currency_id is None:
|
||||
currency_id = self.currency_id.id
|
||||
|
||||
vals_account = {'currency_id': currency_id, 'acc_name': account_number, 'account_type': 'bank'}
|
||||
vals_account = MultiChartsAccounts._prepare_bank_account(self, vals_account)
|
||||
account_id = self.env['account.account'].create(vals_account).id
|
||||
|
||||
vals_journal = {'currency_id': currency_id, 'acc_name': _('Bank') + ' ' + account_number, 'account_type': 'bank'}
|
||||
vals_journal = MultiChartsAccounts._prepare_bank_journal(self, vals_journal, account_id)
|
||||
return self.env['account.journal'].create(vals_journal).id
|
||||
|
||||
@api.multi
|
||||
def compute_fiscalyear_dates(self, date):
|
||||
""" Computes the start and end dates of the fiscalyear where the given 'date' belongs to
|
||||
|
||||
@@ -26,11 +26,11 @@ class TestPayment(AccountingTestCase):
|
||||
self.account_payable = self.env['account.account'].search([('user_type', '=', self.env.ref('account.data_account_type_payable').id)])[0]
|
||||
self.account_revenue = self.env['account.account'].search([('user_type', '=', self.env.ref('account.data_account_type_revenue').id)])[0]
|
||||
|
||||
self.bank_euro = self.env['res.partner.bank'].create({'acc_number': '0123456789', 'bank_name': 'Test Bank'})
|
||||
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.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'})
|
||||
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.account_usd = self.bank_journal_usd.default_debit_account_id
|
||||
self.account_usd.write({'currency_id': self.currency_usd_id})
|
||||
@@ -40,7 +40,6 @@ class TestPayment(AccountingTestCase):
|
||||
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
|
||||
|
||||
|
||||
def create_invoice(self, amount=100, type='out_invoice', currency_id=None):
|
||||
""" Returns an open invoice """
|
||||
invoice = self.invoice_model.create({
|
||||
|
||||
@@ -25,12 +25,12 @@ class TestReconciliation(AccountingTestCase):
|
||||
self.account_rsa = self.env['account.account'].search([('user_type', '=', self.env.ref('account.data_account_type_payable').id)])[0]
|
||||
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'})
|
||||
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.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'})
|
||||
'bank_name': 'Test Bank USD', 'company_id': self.env.user.company_id.id})
|
||||
self.bank_journal_usd = self.bank_usd.journal_id
|
||||
self.account_usd = self.bank_journal_usd.default_debit_account_id
|
||||
self.account_usd.write({'currency_id': self.currency_usd_id})
|
||||
|
||||
@@ -82,8 +82,9 @@
|
||||
<field name="destination_journal_id" widget="selection" attrs="{'required': [('payment_type', '=', 'transfer')], 'invisible': [('payment_type', '!=', 'transfer')], 'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="hide_payment_method" invisible="1"/>
|
||||
<field name="payment_method" widget="radio" attrs="{'invisible': [('hide_payment_method', '=', True)], 'readonly': [('state', '!=', 'draft')]}" String="Payment Mode"/>
|
||||
<field name="payment_method_code" invisible="1"/>
|
||||
<label for="amount"/>
|
||||
<div>
|
||||
<div name="amount_div">
|
||||
<field name="amount" class="oe_inline" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
<field name="currency_id" groups="base.group_multi_currency" class="oe_inline" attrs="{'readonly': [('state', '!=', 'draft')]}"/>
|
||||
</div>
|
||||
@@ -161,8 +162,9 @@
|
||||
<field name="journal_id" widget="selection"/>
|
||||
<field name="hide_payment_method" invisible="1"/>
|
||||
<field name="payment_method" widget="radio" attrs="{'invisible': [('hide_payment_method', '=', True)]}"/>
|
||||
<field name="payment_method_code" invisible="1"/>
|
||||
<label for="amount"/>
|
||||
<div>
|
||||
<div name="amount_div">
|
||||
<field name="amount" class="oe_inline"/>
|
||||
<field name="currency_id" groups="base.group_multi_currency" class="oe_inline"/>
|
||||
</div>
|
||||
@@ -209,11 +211,14 @@
|
||||
<field name="arch" type="xml">
|
||||
<form string="Register Payment" version="7">
|
||||
<field name="payment_type" invisible="1"/>
|
||||
<field name="partner_type" invisible="1"/>
|
||||
<field name="partner_id" invisible="1"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="journal_id" widget="selection"/>
|
||||
<field name="hide_payment_method" invisible="1"/>
|
||||
<field name="payment_method" widget="radio" attrs="{'invisible': [('hide_payment_method', '=', True)]}"/>
|
||||
<field name="payment_method_code" invisible="1"/>
|
||||
<label for="amount" />
|
||||
<div>
|
||||
<field name="amount" class="oe_inline"/>
|
||||
|
||||
@@ -254,14 +254,14 @@
|
||||
<field name="type"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="default_debit_account_id" attrs="{'required':[('type','in', ('cash', 'bank'))]}" domain="[('deprecated', '=', False)]"/>
|
||||
<field name="default_credit_account_id" attrs="{'required':[('type','in',('cash', 'bank'))]}" domain="[('deprecated', '=', False)]"/>
|
||||
<field name="default_debit_account_id" domain="[('deprecated', '=', False)]"/>
|
||||
<field name="default_credit_account_id" domain="[('deprecated', '=', False)]"/>
|
||||
<field name="currency_id" groups="base.group_multi_currency"/>
|
||||
<field name="company_id" groups="base.group_multi_company"/>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="Advanced Settings">
|
||||
<page name="advanced_settings" string="Advanced Settings">
|
||||
<group>
|
||||
<group>
|
||||
<field name="type_control_ids" widget="many2many_tags"/>
|
||||
@@ -1456,29 +1456,6 @@
|
||||
<field name="search_view_id" ref="view_account_template_search"/>
|
||||
</record>
|
||||
|
||||
<record id="view_account_addtmpl_wizard_form" model="ir.ui.view">
|
||||
<field name="name">Create Account</field>
|
||||
<field name="model">account.addtmpl.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Create Account">
|
||||
<header>
|
||||
<button icon="gtk-ok" name="action_create" string="Add" type="object" class="oe_highlight" />
|
||||
</header>
|
||||
<separator col="4" colspan="4" string="Create an Account Based on this Template"/>
|
||||
<field name="cparent_id"/>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<act_window domain="[]" id="action_account_addtmpl_wizard_form"
|
||||
name="Create Account"
|
||||
target="new"
|
||||
res_model="account.addtmpl.wizard"
|
||||
context="{'tmpl_ids': active_id}"
|
||||
src_model="account.account.template"
|
||||
view_type="form" view_mode="form"/>
|
||||
|
||||
|
||||
<!-- Chart of Accounts Templates -->
|
||||
<record id="view_account_chart_template_form" model="ir.ui.view">
|
||||
<field name="name">account.chart.template.form</field>
|
||||
|
||||
@@ -44,7 +44,7 @@ class AccountBankStatementImport(models.TransientModel):
|
||||
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, partner_id=self.env.uid)
|
||||
rec._create_bank_account(account_number, journal_id=journal_id)
|
||||
# Prepare statement data to be used for bank statements creation
|
||||
stmts_vals = rec._complete_stmts_vals(stmts_vals, journal_id, account_number)
|
||||
# Create the bank statements
|
||||
@@ -145,7 +145,9 @@ class AccountBankStatementImport(models.TransientModel):
|
||||
|
||||
# If there is no journal, create one (and its account)
|
||||
if not journal_id and account_number:
|
||||
journal_id = self.env.user.company_id._create_bank_account_and_journal(account_number, currency_id)
|
||||
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})
|
||||
|
||||
@@ -154,7 +156,7 @@ class AccountBankStatementImport(models.TransientModel):
|
||||
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, partner_id=False):
|
||||
def _create_bank_account(self, account_number, journal_id=False):
|
||||
try:
|
||||
bank_type = self.env.ref('bank.bank_normal')
|
||||
bank_code = bank_type.code
|
||||
@@ -167,11 +169,10 @@ class AccountBankStatementImport(models.TransientModel):
|
||||
}
|
||||
# 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.
|
||||
# Warning : if company_id is set, the method post_write of class bank will create a journal
|
||||
if journal_id:
|
||||
vals_acc['partner_id'] = self.env.uid
|
||||
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)
|
||||
|
||||
@@ -184,7 +185,7 @@ class AccountBankStatementImport(models.TransientModel):
|
||||
if unique_import_id:
|
||||
line_vals['unique_import_id'] = (account_number and account_number + '-' or '') + unique_import_id
|
||||
|
||||
if not 'bank_account_id' in line_vals or not line_vals['bank_account_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
|
||||
# reconciliation process will be linked to the bank when the statement is closed.
|
||||
partner_id = False
|
||||
@@ -196,6 +197,8 @@ 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
|
||||
line_vals['partner_id'] = partner_id
|
||||
line_vals['bank_account_id'] = bank_account_id
|
||||
|
||||
@@ -1,42 +1,42 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
from openerp import api, fields, models
|
||||
|
||||
class account_bank_statement_import_journal_creation(osv.TransientModel):
|
||||
class account_bank_statement_import_journal_creation(models.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']
|
||||
name = fields.Char('Journal Name', required=True)
|
||||
currency_id = fields.Many2one('res.currency', 'Currency', readonly=True)
|
||||
account_number = fields.Char('Account Number', readonly=True)
|
||||
|
||||
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]
|
||||
@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
|
||||
|
||||
# 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)
|
||||
bank_account_id = self.env._context.get('bank_account_id')
|
||||
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)
|
||||
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(cr, uid, context['statement_import_transient_id'], context=context)
|
||||
statement_import_transient = import_wiz_obj.browse(self.env._context['statement_import_transient_id'])
|
||||
return statement_import_transient.import_file()
|
||||
|
||||
@@ -19,7 +19,9 @@ class TestQifFile(TransactionCase):
|
||||
bank_statement_id = self.BankStatementImport.create(dict(
|
||||
data_file=qif_file,
|
||||
))
|
||||
journal = self.env.user.company_id._create_bank_account_and_journal('Bank Account (test import qif)')
|
||||
bank_statement_id.with_context(journal_id=journal).import_file()
|
||||
company = self.env.user.company_id
|
||||
journal_vals = self.env['account.journal']._prepare_bank_journal(company, {'account_type': 'bank', 'acc_name': 'Bank Account (test import qif)'})
|
||||
journal = self.env['account.journal'].create(journal_vals)
|
||||
bank_statement_id.with_context(journal_id=journal.id).import_file()
|
||||
line = self.BankStatementLine.search([('name', '=', 'YOUR LOCAL SUPERMARKET')], limit=1)
|
||||
assert float_compare(line.statement_id.balance_end_real, -1896.09, 2) == 0
|
||||
|
||||
@@ -26,12 +26,13 @@
|
||||
This module installs the base for IBAN (International Bank Account Number) bank accounts and checks for it's validity.
|
||||
======================================================================================================================
|
||||
|
||||
The ability to extract the correctly represented local accounts from IBAN accounts
|
||||
The ability to extract the correctly represented local accounts from IBAN accounts
|
||||
with a single statement.
|
||||
""",
|
||||
'author': 'OpenERP SA',
|
||||
'website': 'https://www.odoo.com',
|
||||
'depends': ['base'],
|
||||
'demo': ['demo/iban_demo.xml'],
|
||||
'data': ['base_iban_data.xml' , 'base_iban_view.xml'],
|
||||
'installable': True,
|
||||
'auto_install': False,
|
||||
|
||||
+127
-165
@@ -1,182 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
##############################################################################
|
||||
#
|
||||
# OpenERP, Open Source Management Solution
|
||||
# Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as
|
||||
# published by the Free Software Foundation, either version 3 of the
|
||||
# License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
##############################################################################
|
||||
import string
|
||||
|
||||
from openerp.osv import fields, osv
|
||||
from openerp.tools.translate import _
|
||||
import re
|
||||
|
||||
# Reference Examples of IBAN
|
||||
_ref_iban = { 'al':'ALkk BBBS SSSK CCCC CCCC CCCC CCCC', 'ad':'ADkk BBBB SSSS CCCC CCCC CCCC',
|
||||
'at':'ATkk BBBB BCCC CCCC CCCC', 'be': 'BEkk BBBC CCCC CCKK', 'ba': 'BAkk BBBS SSCC CCCC CCKK',
|
||||
'bg': 'BGkk BBBB SSSS DDCC CCCC CC', 'bh': 'BHkk BBBB SSSS SSSS SSSS SS',
|
||||
'cr': 'CRkk BBBC CCCC CCCC CCCC C',
|
||||
'hr': 'HRkk BBBB BBBC CCCC CCCC C', 'cy': 'CYkk BBBS SSSS CCCC CCCC CCCC CCCC',
|
||||
'cz': 'CZkk BBBB SSSS SSCC CCCC CCCC', 'dk': 'DKkk BBBB CCCC CCCC CC',
|
||||
'do': 'DOkk BBBB CCCC CCCC CCCC CCCC CCCC',
|
||||
'ee': 'EEkk BBSS CCCC CCCC CCCK', 'fo': 'FOkk CCCC CCCC CCCC CC',
|
||||
'fi': 'FIkk BBBB BBCC CCCC CK', 'fr': 'FRkk BBBB BGGG GGCC CCCC CCCC CKK',
|
||||
'ge': 'GEkk BBCC CCCC CCCC CCCC CC', 'de': 'DEkk BBBB BBBB CCCC CCCC CC',
|
||||
'gi': 'GIkk BBBB CCCC CCCC CCCC CCC', 'gr': 'GRkk BBBS SSSC CCCC CCCC CCCC CCC',
|
||||
'gl': 'GLkk BBBB CCCC CCCC CC', 'hu': 'HUkk BBBS SSSC CCCC CCCC CCCC CCCC',
|
||||
'is':'ISkk BBBB SSCC CCCC XXXX XXXX XX', 'ie': 'IEkk BBBB SSSS SSCC CCCC CC',
|
||||
'il': 'ILkk BBBS SSCC CCCC CCCC CCC', 'it': 'ITkk KBBB BBSS SSSC CCCC CCCC CCC',
|
||||
'kz': 'KZkk BBBC CCCC CCCC CCCC', 'kw': 'KWkk BBBB CCCC CCCC CCCC CCCC CCCC CC',
|
||||
'lv': 'LVkk BBBB CCCC CCCC CCCC C',
|
||||
'lb': 'LBkk BBBB CCCC CCCC CCCC CCCC CCCC', 'li': 'LIkk BBBB BCCC CCCC CCCC C',
|
||||
'lt': 'LTkk BBBB BCCC CCCC CCCC', 'lu': 'LUkk BBBC CCCC CCCC CCCC' ,
|
||||
'mk': 'MKkk BBBC CCCC CCCC CKK', 'mt': 'MTkk BBBB SSSS SCCC CCCC CCCC CCCC CCC',
|
||||
'mr': 'MRkk BBBB BSSS SSCC CCCC CCCC CKK',
|
||||
'mu': 'MUkk BBBB BBSS CCCC CCCC CCCC CCCC CC', 'mc': 'MCkk BBBB BGGG GGCC CCCC CCCC CKK',
|
||||
'me': 'MEkk BBBC CCCC CCCC CCCC KK',
|
||||
'nl': 'NLkk BBBB CCCC CCCC CC', 'no': 'NOkk BBBB CCCC CCK',
|
||||
'pl':'PLkk BBBS SSSK CCCC CCCC CCCC CCCC',
|
||||
'pt': 'PTkk BBBB SSSS CCCC CCCC CCCK K', 'ro': 'ROkk BBBB CCCC CCCC CCCC CCCC',
|
||||
'sm': 'SMkk KBBB BBSS SSSC CCCC CCCC CCC', 'sa': 'SAkk BBCC CCCC CCCC CCCC CCCC',
|
||||
'rs': 'RSkk BBBC CCCC CCCC CCCC KK', 'sk': 'SKkk BBBB SSSS SSCC CCCC CCCC',
|
||||
'si': 'SIkk BBSS SCCC CCCC CKK', 'es': 'ESkk BBBB SSSS KKCC CCCC CCCC',
|
||||
'se': 'SEkk BBBB CCCC CCCC CCCC CCCC', 'ch': 'CHkk BBBB BCCC CCCC CCCC C',
|
||||
'tn': 'TNkk BBSS SCCC CCCC CCCC CCCC', 'tr': 'TRkk BBBB BRCC CCCC CCCC CCCC CC',
|
||||
'ae': 'AEkk BBBC CCCC CCCC CCCC CCC',
|
||||
'gb': 'GBkk BBBB SSSS SSCC CCCC CC',
|
||||
}
|
||||
from openerp import models, api, _
|
||||
from openerp.exceptions import UserError, ValidationError
|
||||
|
||||
def _format_iban(iban_str):
|
||||
'''
|
||||
This function removes all characters from given 'iban_str' that isn't a alpha numeric and converts it to upper case.
|
||||
'''
|
||||
res = ""
|
||||
if iban_str:
|
||||
for char in iban_str:
|
||||
if char.isalnum():
|
||||
res += char.upper()
|
||||
return res
|
||||
|
||||
def _pretty_iban(iban_str):
|
||||
"return iban_str in groups of four characters separated by a single space"
|
||||
res = []
|
||||
while iban_str:
|
||||
res.append(iban_str[:4])
|
||||
iban_str = iban_str[4:]
|
||||
return ' '.join(res)
|
||||
def normalize_iban(iban):
|
||||
return re.sub('[\W_]', '', iban)
|
||||
|
||||
class res_partner_bank(osv.osv):
|
||||
def pretty_iban(iban):
|
||||
""" return iban in groups of four characters separated by a single space """
|
||||
return ' '.join([iban[i:i + 4] for i in range(0, len(iban), 4)])
|
||||
|
||||
def get_bban_from_iban(iban):
|
||||
""" Returns the basic bank account number corresponding to an IBAN.
|
||||
Note : the BBAN is not the same as the domestic bank account number !
|
||||
The relation between IBAN, BBAN and domestic can be found here : http://www.ecbs.org/iban.htm
|
||||
"""
|
||||
return normalize_iban(iban)[4:]
|
||||
|
||||
def validate_iban(iban):
|
||||
iban = normalize_iban(iban)
|
||||
if not iban:
|
||||
raise ValidationError(_("No IBAN !"))
|
||||
|
||||
country_code = iban[:2].lower()
|
||||
if country_code not in _map_iban_template:
|
||||
raise ValidationError(_("The IBAN is invalid, it should begin with the country code"))
|
||||
|
||||
iban_template = _map_iban_template[country_code]
|
||||
if len(iban) != len(iban_template.replace(' ', '')):
|
||||
raise ValidationError(_("The IBAN does not seem to be correct. You should have entered something like this %s\n"\
|
||||
"Where B = National bank code, S = Branch code, C = Account No, k = Check digit" % iban_template))
|
||||
|
||||
check_chars = iban[4:] + iban[:4]
|
||||
digits = int(''.join(str(int(char, 36)) for char in check_chars)) # BASE 36: 0..9,A..Z -> 0..35
|
||||
if digits % 97 != 1:
|
||||
raise ValidationError(_("This IBAN does not pass the validation check, please verify it."))
|
||||
|
||||
|
||||
class res_partner_bank(models.Model):
|
||||
_inherit = "res.partner.bank"
|
||||
|
||||
def get_bban(self):
|
||||
if self.state != 'iban':
|
||||
raise UserError(_("Cannot compute the BBAN because the account number is not an IBAN."))
|
||||
return get_bban_from_iban(self.acc_number)
|
||||
|
||||
def create(self, cr, uid, vals, context=None):
|
||||
#overwrite to format the iban number correctly
|
||||
if (vals.get('state',False)=='iban') and vals.get('acc_number', False):
|
||||
vals['acc_number'] = _format_iban(vals['acc_number'])
|
||||
vals['acc_number'] = _pretty_iban(vals['acc_number'])
|
||||
if (vals.get('state') == 'iban') and vals.get('acc_number'):
|
||||
vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number']))
|
||||
return super(res_partner_bank, self).create(cr, uid, vals, context)
|
||||
|
||||
def write(self, cr, uid, ids, vals, context=None):
|
||||
#overwrite to format the iban number correctly
|
||||
if (vals.get('state',False)=='iban') and vals.get('acc_number', False):
|
||||
vals['acc_number'] = _format_iban(vals['acc_number'])
|
||||
vals['acc_number'] = _pretty_iban(vals['acc_number'])
|
||||
if (vals.get('state') == 'iban') and vals.get('acc_number'):
|
||||
vals['acc_number'] = pretty_iban(normalize_iban(vals['acc_number']))
|
||||
return super(res_partner_bank, self).write(cr, uid, ids, vals, context)
|
||||
|
||||
def is_iban_valid(self, cr, uid, iban, context=None):
|
||||
""" Check if IBAN is valid or not
|
||||
@param iban: IBAN as string
|
||||
@return: True if IBAN is valid, False otherwise
|
||||
"""
|
||||
if not iban:
|
||||
return False
|
||||
iban = _format_iban(iban).lower()
|
||||
if iban[:2] in _ref_iban and len(iban) != len(_format_iban(_ref_iban[iban[:2]])):
|
||||
return False
|
||||
#the four first digits have to be shifted to the end
|
||||
iban = iban[4:] + iban[:4]
|
||||
#letters have to be transformed into numbers (a = 10, b = 11, ...)
|
||||
iban2 = ""
|
||||
for char in iban:
|
||||
if char.isalpha():
|
||||
iban2 += str(ord(char)-87)
|
||||
else:
|
||||
iban2 += char
|
||||
#iban is correct if modulo 97 == 1
|
||||
return int(iban2) % 97 == 1
|
||||
@api.one
|
||||
@api.constrains('state', 'acc_number')
|
||||
def _check_iban(self):
|
||||
if self.state == 'iban':
|
||||
validate_iban(self.acc_number)
|
||||
|
||||
def check_iban(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
Check the IBAN number
|
||||
'''
|
||||
for bank_acc in self.browse(cr, uid, ids, context=context):
|
||||
if bank_acc.state != 'iban':
|
||||
continue
|
||||
if not self.is_iban_valid(cr, uid, bank_acc.acc_number, context=context):
|
||||
return False
|
||||
return True
|
||||
@api.one
|
||||
@api.constrains('state', 'bank_bic')
|
||||
def _check_bank_bic(self):
|
||||
if self.state == 'iban' and not self.bank_bic:
|
||||
raise ValidationError(_("Please define BIC/Swift code on bank for bank type IBAN Account to make valid payments."))
|
||||
|
||||
def _construct_constraint_msg(self, cr, uid, ids, context=None):
|
||||
|
||||
def default_iban_check(iban_cn):
|
||||
return iban_cn and iban_cn[0] in string.ascii_lowercase and iban_cn[1] in string.ascii_lowercase
|
||||
|
||||
iban_country = self.browse(cr, uid, ids)[0].acc_number and self.browse(cr, uid, ids)[0].acc_number[:2].lower()
|
||||
if default_iban_check(iban_country):
|
||||
if iban_country in _ref_iban:
|
||||
return _('The IBAN does not seem to be correct. You should have entered something like this %s'), \
|
||||
('%s \nWhere B = National bank code, S = Branch code,'\
|
||||
' C = Account No, K = Check digit' % _ref_iban[iban_country])
|
||||
return _('This IBAN does not pass the validation check, please verify it'), ()
|
||||
return _('The IBAN is invalid, it should begin with the country code'), ()
|
||||
|
||||
def _check_bank(self, cr, uid, ids, context=None):
|
||||
for partner_bank in self.browse(cr, uid, ids, context=context):
|
||||
if partner_bank.state == 'iban' and not partner_bank.bank.bic:
|
||||
return False
|
||||
return True
|
||||
|
||||
def get_bban_from_iban(self, cr, uid, ids, context=None):
|
||||
'''
|
||||
This function returns the bank account number computed from the iban account number, thanks to the mapping_list dictionary that contains the rules associated to its country.
|
||||
'''
|
||||
res = {}
|
||||
mapping_list = {
|
||||
#TODO add rules for others countries
|
||||
'be': lambda x: x[4:],
|
||||
'fr': lambda x: x[14:],
|
||||
'ch': lambda x: x[9:],
|
||||
'gb': lambda x: x[14:],
|
||||
}
|
||||
for record in self.browse(cr, uid, ids, context=context):
|
||||
if not record.acc_number:
|
||||
res[record.id] = False
|
||||
continue
|
||||
res[record.id] = False
|
||||
for code, function in mapping_list.items():
|
||||
if record.acc_number.lower().startswith(code):
|
||||
res[record.id] = function(record.acc_number)
|
||||
break
|
||||
return res
|
||||
|
||||
_columns = {
|
||||
# Deprecated: we keep it for backward compatibility, to be removed in v7
|
||||
# We use acc_number instead of IBAN since v6.1, but we keep this field
|
||||
# to not break community modules.
|
||||
'iban': fields.related('acc_number', string='IBAN', size=34, readonly=True, help="International Bank Account Number", type="char"),
|
||||
}
|
||||
_constraints = [
|
||||
(check_iban, _construct_constraint_msg, ["iban", "acc_number", "state"]),
|
||||
(_check_bank, '\nPlease define BIC/Swift code on bank for bank type IBAN Account to make valid payments', ['bic'])
|
||||
]
|
||||
# Map ISO 3166-1 -> IBAN template, as described here :
|
||||
# http://en.wikipedia.org/wiki/International_Bank_Account_Number#IBAN_formats_by_country
|
||||
_map_iban_template = {
|
||||
'ad': 'ADkk BBBB SSSS CCCC CCCC CCCC', # Andorra
|
||||
'ae': 'AEkk BBBC CCCC CCCC CCCC CCC', # United Arab Emirates
|
||||
'al': 'ALkk BBBS SSSK CCCC CCCC CCCC CCCC', # Albania
|
||||
'at': 'ATkk BBBB BCCC CCCC CCCC', # Austria
|
||||
'az': 'AZkk BBBB CCCC CCCC CCCC CCCC CCCC', # Azerbaijan
|
||||
'ba': 'BAkk BBBS SSCC CCCC CCKK', # Bosnia and Herzegovina
|
||||
'be': 'BEkk BBBC CCCC CCXX', # Belgium
|
||||
'bg': 'BGkk BBBB SSSS DDCC CCCC CC', # Bulgaria
|
||||
'bh': 'BHkk BBBB CCCC CCCC CCCC CC', # Bahrain
|
||||
'br': 'BRkk BBBB BBBB SSSS SCCC CCCC CCCT N', # Brazil
|
||||
'ch': 'CHkk BBBB BCCC CCCC CCCC C', # Switzerland
|
||||
'cr': 'CRkk BBBC CCCC CCCC CCCC C', # Costa Rica
|
||||
'cy': 'CYkk BBBS SSSS CCCC CCCC CCCC CCCC', # Cyprus
|
||||
'cz': 'CZkk BBBB SSSS SSCC CCCC CCCC', # Czech Republic
|
||||
'de': 'DEkk BBBB BBBB CCCC CCCC CC', # Germany
|
||||
'dk': 'DKkk BBBB CCCC CCCC CC', # Denmark
|
||||
'do': 'DOkk BBBB CCCC CCCC CCCC CCCC CCCC', # Dominican Republic
|
||||
'ee': 'EEkk BBSS CCCC CCCC CCCK', # Estonia
|
||||
'es': 'ESkk BBBB SSSS KKCC CCCC CCCC', # Spain
|
||||
'fi': 'FIkk BBBB BBCC CCCC CK', # Finland
|
||||
'fo': 'FOkk CCCC CCCC CCCC CC', # Faroe Islands
|
||||
'fr': 'FRkk BBBB BGGG GGCC CCCC CCCC CKK', # France
|
||||
'gb': 'GBkk BBBB SSSS SSCC CCCC CC', # United Kingdom
|
||||
'ge': 'GEkk BBCC CCCC CCCC CCCC CC', # Georgia
|
||||
'gi': 'GIkk BBBB CCCC CCCC CCCC CCC', # Gibraltar
|
||||
'gl': 'GLkk BBBB CCCC CCCC CC', # Greenland
|
||||
'gr': 'GRkk BBBS SSSC CCCC CCCC CCCC CCC', # Greece
|
||||
'gt': 'GTkk BBBB MMTT CCCC CCCC CCCC CCCC', # Guatemala
|
||||
'hr': 'HRkk BBBB BBBC CCCC CCCC C', # Croatia
|
||||
'hu': 'HUkk BBBS SSSC CCCC CCCC CCCC CCCC', # Hungary
|
||||
'ie': 'IEkk BBBB SSSS SSCC CCCC CC', # Ireland
|
||||
'il': 'ILkk BBBS SSCC CCCC CCCC CCC', # Israel
|
||||
'is': 'ISkk BBBB SSCC CCCC XXXX XXXX XX', # Iceland
|
||||
'it': 'ITkk KBBB BBSS SSSC CCCC CCCC CCC', # Italy
|
||||
'jo': 'JOkk BBBB NNNN CCCC CCCC CCCC CCCC CC', # Jordan
|
||||
'kw': 'KWkk BBBB CCCC CCCC CCCC CCCC CCCC CC', # Kuwait
|
||||
'kz': 'KZkk BBBC CCCC CCCC CCCC', # Kazakhstan
|
||||
'lb': 'LBkk BBBB CCCC CCCC CCCC CCCC CCCC', # Lebanon
|
||||
'li': 'LIkk BBBB BCCC CCCC CCCC C', # Liechtenstein
|
||||
'lt': 'LTkk BBBB BCCC CCCC CCCC', # Lithuania
|
||||
'lu': 'LUkk BBBC CCCC CCCC CCCC', # Luxembourg
|
||||
'lv': 'LVkk BBBB CCCC CCCC CCCC C', # Latvia
|
||||
'mc': 'MCkk BBBB BGGG GGCC CCCC CCCC CKK', # Monaco
|
||||
'md': 'MDkk BBCC CCCC CCCC CCCC CCCC', # Moldova
|
||||
'me': 'MEkk BBBC CCCC CCCC CCCC KK', # Montenegro
|
||||
'mk': 'MKkk BBBC CCCC CCCC CKK', # Macedonia
|
||||
'mr': 'MRkk BBBB BSSS SSCC CCCC CCCC CKK', # Mauritania
|
||||
'mt': 'MTkk BBBB SSSS SCCC CCCC CCCC CCCC CCC', # Malta
|
||||
'mu': 'MUkk BBBB BBSS CCCC CCCC CCCC CCCC CC', # Mauritius
|
||||
'nl': 'NLkk BBBB CCCC CCCC CC', # Netherlands
|
||||
'no': 'NOkk BBBB CCCC CCK', # Norway
|
||||
'pk': 'PKkk BBBB CCCC CCCC CCCC CCCC', # Pakistan
|
||||
'pl': 'PLkk BBBS SSSK CCCC CCCC CCCC CCCC', # Poland
|
||||
'ps': 'PSkk BBBB XXXX XXXX XCCC CCCC CCCC C', # Palestinian
|
||||
'pt': 'PTkk BBBB SSSS CCCC CCCC CCCK K', # Portugal
|
||||
'qa': 'QAkk BBBB CCCC CCCC CCCC CCCC CCCC C', # Qatar
|
||||
'ro': 'ROkk BBBB CCCC CCCC CCCC CCCC', # Romania
|
||||
'rs': 'RSkk BBBC CCCC CCCC CCCC KK', # Serbia
|
||||
'sa': 'SAkk BBCC CCCC CCCC CCCC CCCC', # Saudi Arabia
|
||||
'se': 'SEkk BBBB CCCC CCCC CCCC CCCC', # Sweden
|
||||
'si': 'SIkk BBSS SCCC CCCC CKK', # Slovenia
|
||||
'sk': 'SKkk BBBB SSSS SSCC CCCC CCCC', # Slovakia
|
||||
'sm': 'SMkk KBBB BBSS SSSC CCCC CCCC CCC', # San Marino
|
||||
'tn': 'TNkk BBSS SCCC CCCC CCCC CCCC', # Tunisia
|
||||
'tr': 'TRkk BBBB BRCC CCCC CCCC CCCC CC', # Turkey
|
||||
'vg': 'VGkk BBBB CCCC CCCC CCCC CCCC', # Virgin Islands
|
||||
'xk': 'XKkk BBBB CCCC CCCC CCCC', # Kosovo
|
||||
}
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<openerp>
|
||||
<data noupdate="1">
|
||||
|
||||
<record id="bank_iban_asustek" model="res.partner.bank">
|
||||
<field name="state">iban</field>
|
||||
<field name="acc_number">BE39103123456719</field>
|
||||
<field name="bank_name">Crelan</field>
|
||||
<field name="bank_bic">NICABEBB</field>
|
||||
<field name="partner_id" ref="base.res_partner_1"/>
|
||||
</record>
|
||||
|
||||
<record id="bank_iban_china_export" model="res.partner.bank">
|
||||
<field name="state">iban</field>
|
||||
<field name="acc_number">SI56191000000123438</field>
|
||||
<field name="bank_name">CBC</field>
|
||||
<field name="bank_bic">CREGBEBB</field>
|
||||
<field name="partner_id" ref="base.res_partner_3"/>
|
||||
</record>
|
||||
|
||||
<record id="bank_iban_main_partner" model="res.partner.bank">
|
||||
<field name="state">iban</field>
|
||||
<field name="acc_number">BE61310126985517</field>
|
||||
<field name="bank_name">ING</field>
|
||||
<field name="bank_bic">BBRUBEBB</field>
|
||||
<field name="partner_id" ref="base.res_partner_4"/>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</openerp>
|
||||
@@ -31,7 +31,6 @@ class TestSale(TestMail):
|
||||
|
||||
def test_sale_to_invoice(self):
|
||||
""" Testing for invoice create,validate and pay with invoicing and payment user."""
|
||||
import time
|
||||
# Usefull models
|
||||
IrModelData = self.env['ir.model.data']
|
||||
partner_obj = self.env['res.partner']
|
||||
@@ -41,9 +40,9 @@ class TestSale(TestMail):
|
||||
group_id = IrModelData.xmlid_to_res_id('account.group_account_invoice') or False
|
||||
product_id = IrModelData.xmlid_to_res_id('product.product_category_3') or False
|
||||
company_id = IrModelData.xmlid_to_res_id('base.main_company') or False
|
||||
journal_id = self.env['res.company'].browse(company_id)._create_bank_account_and_journal('BNK')
|
||||
account_id = journal_obj.browse(journal_id).default_credit_account_id.id
|
||||
date = time.strftime("%Y/%m/%d")
|
||||
company = self.env['res.company'].browse(company_id)
|
||||
journal_vals = journal_obj._prepare_bank_journal(company, {'account_type': 'bank', 'acc_name': 'BNK'})
|
||||
journal = journal_obj.create(journal_vals)
|
||||
|
||||
# Usefull accounts
|
||||
user_type_id = IrModelData.xmlid_to_res_id('account.data_account_type_revenue')
|
||||
|
||||
@@ -29,7 +29,6 @@
|
||||
</record>
|
||||
|
||||
<record model="res.partner.bank" id="bank_company">
|
||||
<field name="name">Your Company Bank</field>
|
||||
<field name="acc_number">BE123456789</field>
|
||||
<field name="partner_id" ref="main_partner" />
|
||||
</record>
|
||||
|
||||
@@ -114,7 +114,6 @@ class res_partner_bank(osv.osv):
|
||||
return value
|
||||
|
||||
_columns = {
|
||||
'name': fields.char('Bank Account'), # to be removed in v6.2 ?
|
||||
'acc_number': fields.char('Account Number', required=True),
|
||||
'bank': fields.many2one('res.bank', 'Bank'),
|
||||
'bank_bic': fields.char('Bank Identifier Code'),
|
||||
@@ -133,7 +132,8 @@ class res_partner_bank(osv.osv):
|
||||
'state': fields.selection(_bank_type_get, 'Bank Account Type',
|
||||
change_default=True),
|
||||
'sequence': fields.integer('Sequence'),
|
||||
'footer': fields.boolean("Display on Reports", help="Display this bank account on the footer of printed documents like invoices and sales orders.")
|
||||
'footer': fields.boolean("Display on Reports", help="Display this bank account on the footer of printed documents like invoices and sales orders."),
|
||||
'currency_id': fields.many2one('res.currency', string='Currency', help="Currency of the bank account and its related journal."),
|
||||
}
|
||||
|
||||
_defaults = {
|
||||
@@ -150,9 +150,6 @@ class res_partner_bank(osv.osv):
|
||||
'state_id': lambda obj, cursor, user, context: obj._default_value(
|
||||
cursor, user, 'state_id', context=context),
|
||||
'name': '/',
|
||||
'company_id': lambda obj, cursor, user, context: obj.pool.get('res.company')._company_default_get(
|
||||
cursor, user, 'res.partner.bank', context=context),
|
||||
'partner_id': lambda obj, cr, uid, context: obj.pool.get('res.users').browse(cr, uid, uid, context).company_id.partner_id
|
||||
}
|
||||
|
||||
def fields_get(self, cr, uid, allfields=None, context=None, write_access=True, attributes=None):
|
||||
@@ -190,7 +187,10 @@ class res_partner_bank(osv.osv):
|
||||
data = dict((k, v or '') for (k, v) in data.iteritems())
|
||||
name = bank_code_format[data['state']] % data
|
||||
except Exception:
|
||||
raise UserError(_("Formating Error") + ':' + _("Invalid Bank Account Type Name format."))
|
||||
raise UserError(_("Bank account name formating error") + ': ' + _("Check the format_layout field set on the Bank Account Type."))
|
||||
if data.get('currency_id'):
|
||||
currency_name = self.pool.get('res.currency').browse(cr, uid, data['currency_id'], context=context).name
|
||||
name += ' (' + currency_name + ')'
|
||||
res.append((data.get('id', False), name))
|
||||
return res
|
||||
|
||||
@@ -219,7 +219,6 @@ class res_partner_bank(osv.osv):
|
||||
result['bank_bic'] = bank.bic
|
||||
return {'value': result}
|
||||
|
||||
|
||||
def onchange_partner_id(self, cr, uid, ids, partner_id, context=None):
|
||||
result = {}
|
||||
if partner_id is not False:
|
||||
@@ -228,7 +227,7 @@ class res_partner_bank(osv.osv):
|
||||
result['owner_name'] = part.name
|
||||
result['street'] = part.street or False
|
||||
result['city'] = part.city or False
|
||||
result['zip'] = part.zip or False
|
||||
result['country_id'] = part.country_id.id
|
||||
result['zip'] = part.zip or False
|
||||
result['country_id'] = part.country_id.id
|
||||
result['state_id'] = part.state_id.id
|
||||
return {'value': result}
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
</p>
|
||||
<p>
|
||||
If you use the accounting application of Odoo, journals and accounts will be created automatically based on these data.
|
||||
</p>
|
||||
</p>
|
||||
</field>
|
||||
</record>
|
||||
<menuitem action="action_res_partner_bank_account_form"
|
||||
|
||||
@@ -152,9 +152,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, {'name': '__bank_test_a', 'state': bank_type[0], 'partner_id': p_aa, 'acc_number': '1234'})
|
||||
b_ab = bank_obj.create(cr, uid, {'name': '__bank_test_b', 'state': bank_type[0], 'partner_id': p_ab, 'acc_number': '5678'})
|
||||
b_ba = bank_obj.create(cr, uid, {'name': '__bank_test_b', 'state': bank_type[0], 'partner_id': p_ba, 'acc_number': '9876'})
|
||||
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})
|
||||
|
||||
# --------------------------------------------------
|
||||
# Test1: basics about the attribute
|
||||
@@ -172,30 +172,30 @@ class test_expression(common.TransactionCase):
|
||||
|
||||
# Do: one2many without _auto_join
|
||||
self._reinit_mock()
|
||||
partner_ids = partner_obj.search(cr, uid, [('bank_ids.name', 'like', name_test)])
|
||||
partner_ids = partner_obj.search(cr, uid, [('bank_ids.acc_number', 'like', name_test)])
|
||||
# Test result
|
||||
self.assertEqual(set(partner_ids), set([p_aa]),
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..'): incorrect result")
|
||||
"_auto_join off: ('bank_ids.acc_number', 'like', '..'): incorrect result")
|
||||
# Test produced queries
|
||||
self.assertEqual(len(self.query_list), 3,
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') should produce 3 queries (1 in res_partner_bank, 2 on res_partner)")
|
||||
"_auto_join off: ('bank_ids.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.name', 'like', '..') first query incorrect main table")
|
||||
"_auto_join off: ('bank_ids.acc_number', 'like', '..') first query incorrect main table")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner_bank"."name"'), unaccent('%s'))
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner_bank"."acc_number"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect where condition")
|
||||
"_auto_join off: ('bank_ids.acc_number', 'like', '..') first query incorrect where condition")
|
||||
|
||||
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') first query incorrect parameter")
|
||||
"_auto_join off: ('bank_ids.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.name', 'like', '..') third query incorrect main table")
|
||||
"_auto_join off: ('bank_ids.acc_number', 'like', '..') third query incorrect main table")
|
||||
self.assertIn('"res_partner"."id" in (%s)', sql_query[1],
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') third query incorrect where condition")
|
||||
"_auto_join off: ('bank_ids.acc_number', 'like', '..') third query incorrect where condition")
|
||||
self.assertEqual(set([p_aa]), set(sql_query[2]),
|
||||
"_auto_join off: ('bank_ids.name', 'like', '..') third query incorrect parameter")
|
||||
"_auto_join off: ('bank_ids.acc_number', 'like', '..') third query incorrect parameter")
|
||||
|
||||
# Do: cascaded one2many without _auto_join
|
||||
self._reinit_mock()
|
||||
@@ -210,27 +210,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.name', 'like', 'test_a')])
|
||||
partner_ids = partner_obj.search(cr, uid, [('bank_ids.acc_number', 'like', 'test_a')])
|
||||
# Test result
|
||||
self.assertEqual(set(partner_ids), set([p_aa]),
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') incorrect result")
|
||||
"_auto_join on: ('bank_ids.acc_number', 'like', '..') incorrect result")
|
||||
# Test produced queries
|
||||
self.assertEqual(len(self.query_list), 1,
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') should produce 1 query")
|
||||
"_auto_join on: ('bank_ids.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.name', 'like', '..') query incorrect main table")
|
||||
"_auto_join on: ('bank_ids.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.name', 'like', '..') query incorrect join")
|
||||
"_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect join")
|
||||
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner__bank_ids"."name"'), unaccent('%s'))
|
||||
expected = "%s::text like %s" % (unaccent('"res_partner__bank_ids"."acc_number"'), unaccent('%s'))
|
||||
self.assertIn(expected, sql_query[1],
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect where condition")
|
||||
"_auto_join on: ('bank_ids.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.name', 'like', '..') query incorrect join condition")
|
||||
"_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect join condition")
|
||||
self.assertEqual(set(['%' + name_test + '%']), set(sql_query[2]),
|
||||
"_auto_join on: ('bank_ids.name', 'like', '..') query incorrect parameter")
|
||||
"_auto_join on: ('bank_ids.acc_number', 'like', '..') query incorrect parameter")
|
||||
|
||||
# Do: one2many with _auto_join, test final leaf is an id
|
||||
self._reinit_mock()
|
||||
@@ -391,7 +391,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', '1')]
|
||||
partner_bank_ids_col._domain = [('acc_number', 'like', 'a')]
|
||||
# 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])])
|
||||
|
||||
@@ -370,7 +370,7 @@
|
||||
# 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, [('name', 'not like', 'probably_unexisting_name')])
|
||||
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'
|
||||
|
||||
Reference in New Issue
Block a user