[FIX] base: clearer message in case of conflict for no_gap sequences

The raw error message from psycopg2 wasn't clear for users and led to
multiple support tickets.

In case of such "concurrency" errors, the user should retry later, it's
not a "real" bug.

closes odoo/odoo#57851

X-original-commit: 9f7f1db5add5b8a940e53707091133c0bcadd350
Signed-off-by: Victor Feyens (vfe) <vfe@odoo.com>
This commit is contained in:
Victor Feyens
2020-09-16 13:18:39 +00:00
parent 152ff868b7
commit 982bd56679
2 changed files with 11 additions and 5 deletions
+9 -3
View File
@@ -3,7 +3,7 @@
from datetime import datetime, timedelta
import logging
import pytz
from psycopg2 import sql
from psycopg2 import sql, OperationalError, errorcodes
from odoo import api, fields, models, _
from odoo.exceptions import UserError
@@ -53,8 +53,14 @@ def _select_nextval(cr, seq_name):
def _update_nogap(self, number_increment):
number_next = self.number_next
self._cr.execute("SELECT number_next FROM %s WHERE id=%%s FOR UPDATE NOWAIT" % self._table, [self.id])
self._cr.execute("UPDATE %s SET number_next=number_next+%%s WHERE id=%%s " % self._table, (number_increment, self.id))
try:
self._cr.execute("SELECT number_next FROM %s WHERE id=%%s FOR UPDATE NOWAIT" % self._table, [self.id])
self._cr.execute("UPDATE %s SET number_next=number_next+%%s WHERE id=%%s " % self._table, (number_increment, self.id))
except OperationalError as e:
if e.pgcode == errorcodes.LOCK_NOT_AVAILABLE:
raise UserError(_("This transaction wasn't executed because another transaction is already using the same no-gap sequence. Please try again later."))
else:
raise
self.invalidate_cache(['number_next'], [self.id])
return number_next
+2 -2
View File
@@ -7,6 +7,7 @@ import psycopg2
import psycopg2.errorcodes
import odoo
from odoo.exceptions import UserError
from odoo.tests import common
from odoo.tests.common import BaseCase
@@ -92,11 +93,10 @@ class TestIrSequenceNoGap(BaseCase):
with environment() as env0:
with environment() as env1:
env1.cr._default_log_exceptions = False # Prevent logging a traceback
with self.assertRaises(psycopg2.OperationalError) as e:
with self.assertRaises(UserError) as e:
n0 = env0['ir.sequence'].next_by_code('test_sequence_type_2')
self.assertTrue(n0)
n1 = env1['ir.sequence'].next_by_code('test_sequence_type_2')
self.assertEqual(e.exception.pgcode, psycopg2.errorcodes.LOCK_NOT_AVAILABLE, msg="postgresql returned an incorrect errcode")
@classmethod
def tearDownClass(cls):