diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py index 7fbc4c07580..69af644a794 100644 --- a/addons/account/models/account_move.py +++ b/addons/account/models/account_move.py @@ -14,6 +14,7 @@ from itertools import zip_longest import json import re import logging +import psycopg2 _logger = logging.getLogger(__name__) @@ -1900,6 +1901,26 @@ class AccountMove(models.Model): # installing Accounting- with bank statements) move.company_id.account_bank_reconciliation_start = move.date + for move in self: + if not move.partner_id: continue + if move.type.startswith('out_'): + field='customer_rank' + elif move.type.startswith('in_'): + field='supplier_rank' + else: + continue + try: + with self.env.cr.savepoint(): + self.env.cr.execute("SELECT "+field+" FROM res_partner WHERE ID=%s FOR UPDATE NOWAIT", (move.partner_id.id,)) + self.env.cr.execute("UPDATE res_partner SET "+field+"="+field+"+1 WHERE ID=%s", (move.partner_id.id,)) + self.env.cache.remove(move.partner_id, move.partner_id._fields[field]) + except psycopg2.DatabaseError as e: + if e.pgcode == '55P03': + _logger.debug('Another transaction already locked partner rows. Cannot update partner ranks.') + continue + else: + raise e + def action_reverse(self): action = self.env.ref('account.action_view_account_move_reversal').read()[0] diff --git a/addons/account/models/partner.py b/addons/account/models/partner.py index c914da34ab2..0b19d281788 100644 --- a/addons/account/models/partner.py +++ b/addons/account/models/partner.py @@ -2,7 +2,6 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. import time -import psycopg2 import logging from odoo import api, fields, models, _ @@ -10,8 +9,6 @@ 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 -_logger = logging.getLogger(__name__) - class AccountFiscalPosition(models.Model): _name = 'account.fiscal.position' _description = 'Fiscal Position' @@ -439,8 +436,8 @@ class ResPartner(models.Model): invoice_warn_msg = fields.Text('Message for Invoice') # Computed fields to order the partners as suppliers/customers according to the # amount of their generated incoming/outgoing account moves - supplier_rank = fields.Integer(compute='_compute_rank', store=True) - customer_rank = fields.Integer(compute='_compute_rank', store=True) + supplier_rank = fields.Integer(default=0) + customer_rank = fields.Integer(default=0) def _get_name_search_order_by_fields(self): res = super()._get_name_search_order_by_fields() @@ -456,67 +453,6 @@ class ResPartner(models.Model): order_by_field = order_by_field % field return '%s, %s' % (res, order_by_field % field) if res else order_by_field - @api.depends('invoice_ids', 'invoice_ids.state') - def _compute_rank(self): - """ - The two field values may not be exact in the database! - To avoid any concurrent update failure while writing on the partner, - the count is not updated if the lock cannot be directly acquired. - The count will eventually be correctly computed, at the next successfull try. - """ - types_in = ('in_invoice', 'in_refund', 'in_receipt') - types_out = ('out_invoice', 'out_refund', 'out_receipt') - partner_ids = tuple(self.ids) - queries_params = { - 'supplier_rank': { - 'partner_id': partner_ids, - 'move_types': types_in - }, - 'customer_rank': { - 'partner_id': partner_ids, - 'move_types': types_out - }, - } - - # Update database in case an invoice is just created - self.flush() - for field, params in queries_params.items(): - try: - with self.env.cr.savepoint(): - # Check if rows are not locked - # Take this opportunity to retrieve the current partner ranks - # If a customer has been created from the "Customer" menuitem - # his rank should be equal to 1, even if no invoice has been - # created for him yet - self.env.cr.execute(""" - SELECT id, COALESCE({}, 0) - FROM res_partner - WHERE id IN %(partner_id)s - FOR UPDATE NOWAIT - """.format(field), params, log_exceptions=False) - current_counts = dict(self.env.cr.fetchall()) - # Compute the real ranks, based on the posted - # account moves generated from the invoices - self.env.cr.execute(""" - SELECT m.partner_id, COUNT(*) AS move_count - FROM account_move AS m - WHERE - type in %(move_types)s - AND state = 'posted' - AND partner_id IN %(partner_id)s - GROUP BY m.partner_id - """, params) - counts = dict(self.env.cr.fetchall()) - # Update all ranks - for partner in self: - partner[field] = max(counts.get(partner.id, 0), current_counts.get(partner.id, 0)) - except psycopg2.DatabaseError as e: - if e.pgcode == '55P03': - _logger.debug('Another transaction already locked partner rows. Cannot update partner ranks now.') - continue - else: - raise e - def _compute_bank_count(self): bank_data = self.env['res.partner.bank'].read_group([('partner_id', 'in', self.ids)], ['partner_id'], ['partner_id']) mapped_data = dict([(bank['partner_id'][0], bank['partner_id_count']) for bank in bank_data]) diff --git a/addons/account/views/partner_view.xml b/addons/account/views/partner_view.xml index 6550a595192..d64d5dc95f3 100644 --- a/addons/account/views/partner_view.xml +++ b/addons/account/views/partner_view.xml @@ -222,7 +222,7 @@ ir.actions.act_window res.partner kanban,tree,form - {'search_default_customer': 1,'res_partner_search_mode': 'customer', 'default_is_company': True} + {'search_default_customer': 1,'res_partner_search_mode': 'customer', 'default_is_company': True, 'default_customer_rank': 1}

Create a new customer in your address book @@ -237,7 +237,7 @@ ir.actions.act_window res.partner kanban,tree,form - {'search_default_supplier': 1,'res_partner_search_mode': 'supplier', 'default_is_company': True} + {'search_default_supplier': 1,'res_partner_search_mode': 'supplier', 'default_is_company': True, 'default_supplier_rank': 1}

Create a new supplier in your address book