From 5c9296a150ab8e1b4881ab270e7d816097285e27 Mon Sep 17 00:00:00 2001 From: Suherdy Yacob Date: Fri, 19 Jun 2026 11:26:28 +0700 Subject: [PATCH] feat: add concurrency checks for POS orders and payments using write_date verification --- models/pos_order.py | 12 ++++++++++++ models/pos_payment.py | 15 ++++++++++++++- 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/models/pos_order.py b/models/pos_order.py index 0c4ce75..73d9b25 100644 --- a/models/pos_order.py +++ b/models/pos_order.py @@ -142,6 +142,18 @@ class PosOrder(models.Model): # Use PostgreSQL transaction-level advisory lock 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) diff --git a/models/pos_payment.py b/models/pos_payment.py index 56b36c3..168ca7b 100644 --- a/models/pos_payment.py +++ b/models/pos_payment.py @@ -18,7 +18,20 @@ class PosPayment(models.Model): for uuid in sorted_uuids: 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 = {} if sorted_uuids: existing_payments = self.search([('uuid', 'in', sorted_uuids)])