mirror of
https://github.com/OCA/stock-logistics-warehouse.git
synced 2025-01-21 14:27:28 +02:00
Merge pull request #1 from TDu/14-procurement_create_group_by_product-add-lock
[IMP] proc_auto_create_grp_by_product: add lock
This commit is contained in:
@@ -1,7 +1,11 @@
|
||||
# Copyright 2023 Jacques-Etienne Baudoux (BCIM) <je@bcim.be>
|
||||
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
|
||||
|
||||
import hashlib
|
||||
import struct
|
||||
|
||||
from odoo import fields, models
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class StockRule(models.Model):
|
||||
@@ -13,6 +17,21 @@ 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."
|
||||
)
|
||||
return super()._get_auto_procurement_group(product)
|
||||
|
||||
def _prepare_auto_procurement_group_data(self, product):
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# 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
|
||||
|
||||
from odoo.addons.procurement_auto_create_group.tests.test_auto_create import (
|
||||
TestProcurementAutoCreateGroup,
|
||||
)
|
||||
@@ -108,3 +111,33 @@ class TestProcurementAutoCreateGroupByProduct(TestProcurementAutoCreateGroup):
|
||||
self.prod_auto_push,
|
||||
"Procurement Group product missing.",
|
||||
)
|
||||
|
||||
def test_concurrent_procurement_group_creation(self):
|
||||
"""Check for the same product, no multiple procurement groups are created."""
|
||||
rule = self.pull_push_rule_auto
|
||||
rule.auto_create_group_by_product = True
|
||||
product = self.prod_auto_pull_push
|
||||
# Check that no procurement group exist for the product
|
||||
self.assertFalse(product.auto_create_procurement_group_ids)
|
||||
# So create one and an adisory lock will be created
|
||||
rule._get_auto_procurement_group(product)
|
||||
self.assertTrue(product.auto_create_procurement_group_ids)
|
||||
# Use another transaction to test the advisory lock
|
||||
with registry(self.env.cr.dbname).cursor() as new_cr:
|
||||
new_env = api.Environment(new_cr, self.env.uid, self.env.context)
|
||||
new_env["product.product"].invalidate_cache(
|
||||
["auto_create_procurement_group_ids"],
|
||||
[
|
||||
product.id,
|
||||
],
|
||||
)
|
||||
rule2 = new_env["stock.rule"].browse(rule.id)
|
||||
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):
|
||||
rule2._get_auto_procurement_group(product2)
|
||||
|
||||
Reference in New Issue
Block a user