[IMP] account_*, l10n_*: allows the same bank account on multiple partners

Some use cases require the use of the same account number on multiple
partners. This will relax the constraints to allows such use cases, and
adapt to avoid setting the partner or bank when we cannot be sure of the
one we should take (on bank statement line, and during reconciliation)

Task id #2692025

closes odoo/odoo#81362

Related: odoo/enterprise#22881
Signed-off-by: Laurent Smet <las@odoo.com>
This commit is contained in:
Nicolas (vin)
2022-01-25 13:52:29 +00:00
parent 9943931c6f
commit 68f4534aa5
7 changed files with 77 additions and 13 deletions
@@ -1250,13 +1250,14 @@ class AccountBankStatementLine(models.Model):
# -------------------------------------------------------------------------
def _find_or_create_bank_account(self):
bank_account = self.env['res.partner.bank'].search(
[('company_id', '=', self.company_id.id), ('acc_number', '=', self.account_number)])
bank_account = self.env['res.partner.bank'].search([
('acc_number', '=', self.account_number),
('partner_id', '=', self.partner_id.id),
])
if not bank_account:
bank_account = self.env['res.partner.bank'].create({
'acc_number': self.account_number,
'partner_id': self.partner_id.id,
'company_id': self.company_id.id,
})
return bank_account
+4 -3
View File
@@ -659,15 +659,16 @@ class AccountJournal(models.Model):
def set_bank_account(self, acc_number, bank_id=None):
""" Create a res.partner.bank (if not exists) and set it as value of the field bank_account_id """
self.ensure_one()
res_partner_bank = self.env['res.partner.bank'].search([('sanitized_acc_number', '=', sanitize_account_number(acc_number)),
('company_id', '=', self.company_id.id)], limit=1)
res_partner_bank = self.env['res.partner.bank'].search([
('sanitized_acc_number', '=', sanitize_account_number(acc_number)),
('partner_id', '=', self.company_id.partner_id.id),
], limit=1)
if res_partner_bank:
self.bank_account_id = res_partner_bank.id
else:
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
+1 -1
View File
@@ -521,7 +521,7 @@ class AccountMove(models.Model):
line.account_id = new_term_account
self._compute_bank_partner_id()
bank_ids = self.bank_partner_id.bank_ids.filtered(lambda bank: bank.company_id is False or bank.company_id == self.company_id)
bank_ids = self.bank_partner_id.bank_ids.filtered(lambda bank: not bank.company_id or bank.company_id == self.company_id)
self.partner_bank_id = bank_ids and bank_ids[0]
# Find the new fiscal position.
+48
View File
@@ -7,6 +7,7 @@ import logging
from psycopg2 import sql, DatabaseError
from odoo import api, fields, models, _
from odoo.osv import expression
from odoo.tools import DEFAULT_SERVER_DATETIME_FORMAT
from odoo.exceptions import ValidationError
from odoo.addons.base.models.res_partner import WARNING_MESSAGE, WARNING_HELP
@@ -483,6 +484,11 @@ class ResPartner(models.Model):
supplier_rank = fields.Integer(default=0)
customer_rank = fields.Integer(default=0)
duplicated_bank_account_partners_count = fields.Integer(
compute='_compute_duplicated_bank_account_partners_count',
help='Technical field holding the amount partners that share the same account number as any set on this partner.',
)
def _get_name_search_order_by_fields(self):
res = super()._get_name_search_order_by_fields()
partner_search_mode = self.env.context.get('res_partner_search_mode')
@@ -503,6 +509,24 @@ class ResPartner(models.Model):
for partner in self:
partner.bank_account_count = mapped_data.get(partner.id, 0)
def _get_duplicated_bank_accounts(self):
self.ensure_one()
if not self.bank_ids:
return self.env['res.partner.bank']
domains = []
for bank in self.bank_ids:
domains.append([('acc_number', '=', bank.acc_number), ('bank_id', '=', bank.bank_id.id)])
domain = expression.OR(domains)
if self.company_id:
domain = expression.AND([domain, [('company_id', 'in', (False, self.company_id.id))]])
domain = expression.AND([domain, [('partner_id', '!=', self._origin.id)]])
return self.env['res.partner.bank'].search(domain)
@api.depends('bank_ids')
def _compute_duplicated_bank_account_partners_count(self):
for partner in self:
partner.duplicated_bank_account_partners_count = len(partner._get_duplicated_bank_accounts())
def _find_accounting_partner(self, partner):
''' Find the partner for which the accounting entries will be created '''
return partner.commercial_partner_id
@@ -523,6 +547,30 @@ class ResPartner(models.Model):
action['context'] = {'default_move_type':'out_invoice', 'move_type':'out_invoice', 'journal_type': 'sale', 'search_default_open': 1}
return action
def action_view_partner_with_same_bank(self):
self.ensure_one()
partners = self._get_duplicated_bank_accounts()
# Open a list view or form view of the partner(s) with the same bank accounts
if self.duplicated_bank_account_partners_count == 1:
action_vals = {
'type': 'ir.actions.act_window',
'res_model': 'res.partner',
'view_mode': 'form',
'res_id': partners.id,
'views': [(False, 'form')],
}
else:
action_vals = {
'name': _("Partners"),
'type': 'ir.actions.act_window',
'res_model': 'res.partner',
'view_mode': 'tree,form',
'views': [(False, 'list'), (False, 'form')],
'domain': [('id', 'in', partners.ids)],
}
return action_vals
def can_edit_vat(self):
''' Can't edit `vat` if there is (non draft) issued invoices. '''
can_edit_vat = super(ResPartner, self).can_edit_vat()
+8 -1
View File
@@ -194,11 +194,18 @@
<field name="inherit_id" ref="base.view_partner_form"/>
<field name="groups_id" eval="[(5,)]"/>
<field name="arch" type="xml">
<xpath expr="//sheet" position="before">
<div groups="account.group_account_invoice,account.group_account_readonly" class="alert alert-warning" role="alert" style="margin-bottom:0px;"
attrs="{'invisible': [('duplicated_bank_account_partners_count', '=', 0)]}">
One or more Bank Accounts set on this partner are also used by other <bold><button class="alert-link" type="object" name="action_view_partner_with_same_bank" role="button" string="Partners" style="padding: 0;vertical-align: baseline;"/></bold>. Please make sure that this is a wanted behavior.
</div>
</xpath>
<page name="sales_purchases" position="after">
<page string="Invoicing" name="accounting" attrs="{'invisible': [('is_company','=',False),('parent_id','!=',False)]}" groups="account.group_account_invoice,account.group_account_readonly">
<field name="duplicated_bank_account_partners_count" invisible="1"/>
<group>
<group string="Bank Accounts" name="banks" groups="account.group_account_invoice,account.group_account_readonly">
<field name="bank_ids" nolabel="1">
<field name="bank_ids" nolabel="1" colspan="2">
<tree editable="bottom">
<field name="sequence" widget="handle"/>
<field name="bank_id"/>
@@ -423,7 +423,12 @@ class AccountEdiFormat(models.Model):
('partner_id.id', '=', invoice_form.partner_id.commercial_partner_id.id)
])
else:
bank = self.env['res.partner.bank'].search([('acc_number', '=', elements[0].text)])
bank = self.env['res.partner.bank'].search([
('acc_number', '=', elements[0].text),
('company_id', '=', invoice_form.company_id.id),
])
if len(bank) > 1:
bank = None
if bank:
invoice_form.partner_bank_id = bank
else:
+6 -4
View File
@@ -83,11 +83,13 @@ class ResPartnerBank(models.Model):
bank_bic = fields.Char(related='bank_id.bic', readonly=False)
sequence = fields.Integer(default=10)
currency_id = fields.Many2one('res.currency', string='Currency')
company_id = fields.Many2one('res.company', 'Company', default=lambda self: self.env.company, ondelete='cascade', readonly=True)
company_id = fields.Many2one('res.company', 'Company', related='partner_id.company_id', store=True, readonly=True)
_sql_constraints = [
('unique_number', 'unique(sanitized_acc_number, company_id)', 'Account Number must be unique'),
]
_sql_constraints = [(
'unique_number',
'unique(sanitized_acc_number, partner_id)',
'The combination Account Number/Partner must be unique.'
)]
@api.depends('acc_number')
def _compute_sanitized_acc_number(self):