feat: add concurrency checks for POS orders and payments using write_date verification

This commit is contained in:
Suherdy Yacob 2026-06-19 11:26:28 +07:00
parent 932db6e5f7
commit 5c9296a150
2 changed files with 26 additions and 1 deletions

View File

@ -142,6 +142,18 @@ class PosOrder(models.Model):
# Use PostgreSQL transaction-level advisory lock # Use PostgreSQL transaction-level advisory lock
self.env.cr.execute("SELECT pg_advisory_xact_lock(hashtext(%s))", (uuid,)) self.env.cr.execute("SELECT pg_advisory_xact_lock(hashtext(%s))", (uuid,))
# Check for concurrent updates that occurred before we acquired the lock
with self.env.registry.cursor() as fresh_cr:
fresh_cr.execute("SELECT write_date FROM pos_order WHERE uuid = %s", (uuid,))
fresh_res = fresh_cr.fetchone()
self.env.cr.execute("SELECT write_date FROM pos_order WHERE uuid = %s", (uuid,))
curr_res = self.env.cr.fetchone()
if fresh_res != curr_res:
from odoo.exceptions import ConcurrencyError
raise ConcurrencyError("Concurrent update detected for order uuid %s. Retrying transaction." % uuid)
return super(PosOrder, self).sync_from_ui(orders) return super(PosOrder, self).sync_from_ui(orders)

View File

@ -18,7 +18,20 @@ class PosPayment(models.Model):
for uuid in sorted_uuids: for uuid in sorted_uuids:
self.env.cr.execute("SELECT pg_advisory_xact_lock(hashtext(%s))", (uuid,)) self.env.cr.execute("SELECT pg_advisory_xact_lock(hashtext(%s))", (uuid,))
# 3. Check which payments already exist in the database # 3. Check for concurrent updates/creations of these payments
if sorted_uuids:
with self.env.registry.cursor() as fresh_cr:
fresh_cr.execute("SELECT uuid, write_date FROM pos_payment WHERE uuid IN %s", (tuple(sorted_uuids),))
fresh_res = dict(fresh_cr.fetchall())
self.env.cr.execute("SELECT uuid, write_date FROM pos_payment WHERE uuid IN %s", (tuple(sorted_uuids),))
curr_res = dict(self.env.cr.fetchall())
if fresh_res != curr_res:
from odoo.exceptions import ConcurrencyError
raise ConcurrencyError("Concurrent update/insertion detected for payment uuids. Retrying transaction.")
# 4. Check which payments already exist in the database using the current snapshot
existing_payments_map = {} existing_payments_map = {}
if sorted_uuids: if sorted_uuids:
existing_payments = self.search([('uuid', 'in', sorted_uuids)]) existing_payments = self.search([('uuid', 'in', sorted_uuids)])