From 68f4534aa5d0c6d900128c93f5a2289c06bb3d14 Mon Sep 17 00:00:00 2001 From: "Nicolas (vin)" Date: Thu, 9 Dec 2021 14:12:10 +0000 Subject: [PATCH] [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 --- .../account/models/account_bank_statement.py | 7 +-- addons/account/models/account_journal.py | 7 +-- addons/account/models/account_move.py | 2 +- addons/account/models/partner.py | 48 +++++++++++++++++++ addons/account/views/partner_view.xml | 9 +++- .../l10n_it_edi/models/account_edi_format.py | 7 ++- odoo/addons/base/models/res_bank.py | 10 ++-- 7 files changed, 77 insertions(+), 13 deletions(-) diff --git a/addons/account/models/account_bank_statement.py b/addons/account/models/account_bank_statement.py index 23797c0b7bc..f6c81bb076a 100644 --- a/addons/account/models/account_bank_statement.py +++ b/addons/account/models/account_bank_statement.py @@ -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 diff --git a/addons/account/models/account_journal.py b/addons/account/models/account_journal.py index 18497f07161..e4520976c7f 100644 --- a/addons/account/models/account_journal.py +++ b/addons/account/models/account_journal.py @@ -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 diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 6035aa5d466..d3dbda2ec68 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -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. diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index 56510f2d2c5..91372bb06d3 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -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() diff --git a/addons/account/views/partner_view.xml b/addons/account/views/partner_view.xml index 9876efeff9e..a93beab0110 100644 --- a/addons/account/views/partner_view.xml +++ b/addons/account/views/partner_view.xml @@ -194,11 +194,18 @@ + + + + - + diff --git a/addons/l10n_it_edi/models/account_edi_format.py b/addons/l10n_it_edi/models/account_edi_format.py index 577b8e077e5..2320ef24158 100644 --- a/addons/l10n_it_edi/models/account_edi_format.py +++ b/addons/l10n_it_edi/models/account_edi_format.py @@ -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: diff --git a/odoo/addons/base/models/res_bank.py b/odoo/addons/base/models/res_bank.py index 885ffb7acb0..f0fb7dd6a63 100644 --- a/odoo/addons/base/models/res_bank.py +++ b/odoo/addons/base/models/res_bank.py @@ -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):