proc_auto_create_grp_by_product: fix raised error

Raise correct error to allow correct catching and retry
This commit is contained in:
Jacques-Etienne Baudoux
2024-04-05 17:45:01 +02:00
parent 6cdd79bb25
commit 6572251603
2 changed files with 35 additions and 23 deletions

View File

@@ -5,7 +5,26 @@ import hashlib
import struct
from odoo import fields, models
from odoo.exceptions import UserError
def pg_advisory_lock(env, int_lock: int):
"""Attempts to acquire a Postgres transactional advisory lock.
Raises an OperationalError LOCK_NOT_AVAILABLE if the lock could not be acquired.
"""
env.cr.execute(
"""
DO $$
BEGIN
IF NOT pg_try_advisory_xact_lock(%s) THEN
RAISE EXCEPTION USING
MESSAGE = 'Lock not available',
ERRCODE = '55P03';
END IF;
END $$;
""",
(int_lock),
)
class StockRule(models.Model):
@@ -17,21 +36,12 @@ class StockRule(models.Model):
if self.auto_create_group_by_product:
if product.auto_create_procurement_group_ids:
return fields.first(product.auto_create_procurement_group_ids)
else:
# Make sure that two transactions can not create a procurement group
# For the same product at the same time.
lock_name = f"product.product,{product.id}-auto-proc-group"
hasher = hashlib.sha1(str(lock_name).encode())
int_lock = struct.unpack("q", hasher.digest()[:8])
self.env.cr.execute(
"SELECT pg_try_advisory_xact_lock(%s);", (int_lock,)
)
lock_acquired = self.env.cr.fetchone()[0]
if not lock_acquired:
raise UserError(
f"The auto procurement group for product {product.name} "
"is already being created by someone else."
)
# Make sure that two transactions cannot create a procurement group
# For the same product at the same time.
lock_name = f"product.product,{product.id}-auto-proc-group"
hasher = hashlib.sha1(str(lock_name).encode())
bigint_lock = struct.unpack("q", hasher.digest()[:8])
pg_advisory_lock(self.env, bigint_lock)
return super()._get_auto_procurement_group(product)
def _prepare_auto_procurement_group_data(self, product):

View File

@@ -1,8 +1,10 @@
# Copyright 2023 Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from odoo import api, registry
from odoo.exceptions import UserError
import psycopg2
from odoo import api, registry, tools
from odoo.service.model import PG_CONCURRENCY_ERRORS_TO_RETRY
from odoo.addons.procurement_auto_create_group.tests.test_auto_create import (
TestProcurementAutoCreateGroup,
@@ -135,9 +137,9 @@ class TestProcurementAutoCreateGroupByProduct(TestProcurementAutoCreateGroup):
rule2.auto_create_group_by_product = True
product2 = new_env["product.product"].browse(product.id)
self.assertFalse(product2.auto_create_procurement_group_ids)
exception_msg = (
f"The auto procurement group for product {product2.name} "
"is already being created by someone else."
)
with self.assertRaisesRegex(UserError, exception_msg):
with self.assertRaises(psycopg2.OperationalError) as cm, tools.mute_logger(
"odoo.sql_db"
):
rule2._get_auto_procurement_group(product2)
self.assertTrue(cm.exception.pgcode in PG_CONCURRENCY_ERRORS_TO_RETRY)
new_cr.rollback()