diff --git a/odoo/addons/base/models/ir_sequence.py b/odoo/addons/base/models/ir_sequence.py index a356ddfaa47..3e13dccdade 100644 --- a/odoo/addons/base/models/ir_sequence.py +++ b/odoo/addons/base/models/ir_sequence.py @@ -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 diff --git a/odoo/addons/base/tests/test_ir_sequence.py b/odoo/addons/base/tests/test_ir_sequence.py index 0fc53012b48..8c27dc18d74 100644 --- a/odoo/addons/base/tests/test_ir_sequence.py +++ b/odoo/addons/base/tests/test_ir_sequence.py @@ -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):