[FIX] account: compute partner ranks at post() + fixes

closes odoo/odoo#36080

Signed-off-by: Fabien Pinckaers <fpodoo@users.noreply.github.com>
This commit is contained in:
Fabien Pinckaers
2019-08-26 10:20:41 +00:00
parent 0ec6acc458
commit 59c6a19878
3 changed files with 25 additions and 68 deletions
+21
View File
@@ -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]
+2 -66
View File
@@ -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])
+2 -2
View File
@@ -222,7 +222,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_customer': 1,'res_partner_search_mode': 'customer', 'default_is_company': True}</field>
<field name="context">{'search_default_customer': 1,'res_partner_search_mode': 'customer', 'default_is_company': True, 'default_customer_rank': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new customer in your address book
@@ -237,7 +237,7 @@
<field name="type">ir.actions.act_window</field>
<field name="res_model">res.partner</field>
<field name="view_mode">kanban,tree,form</field>
<field name="context">{'search_default_supplier': 1,'res_partner_search_mode': 'supplier', 'default_is_company': True}</field>
<field name="context">{'search_default_supplier': 1,'res_partner_search_mode': 'supplier', 'default_is_company': True, 'default_supplier_rank': 1}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
Create a new supplier in your address book