pos_ui_optimization/models/pos_payment.py

67 lines
2.7 KiB
Python

# -*- coding: utf-8 -*-
from odoo import models, api
class PosPayment(models.Model):
_inherit = 'pos.payment'
@api.model_create_multi
def create(self, vals_list):
# 1. Extract and sort unique uuids to prevent deadlocks
uuids = []
for vals in vals_list:
if isinstance(vals, dict) and vals.get('uuid'):
uuids.append(vals['uuid'])
sorted_uuids = sorted(list(set(uuids)))
# 2. Acquire transaction-level PostgreSQL advisory locks on the sorted hashes of uuids
for uuid in sorted_uuids:
self.env.cr.execute("SELECT pg_advisory_xact_lock(hashtext(%s))", (uuid,))
# 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)])
for payment in existing_payments:
existing_payments_map[payment.uuid] = payment
# 4. Prepare values to create (only those that don't already exist)
final_payments_list = [None] * len(vals_list)
vals_to_create = []
create_indices = []
for i, vals in enumerate(vals_list):
uuid = vals.get('uuid') if isinstance(vals, dict) else None
if uuid and uuid in existing_payments_map:
final_payments_list[i] = existing_payments_map[uuid]
else:
vals_to_create.append(vals)
create_indices.append(i)
# 5. Create new payments
if vals_to_create:
created_payments = super(PosPayment, self).create(vals_to_create)
for idx, payment in zip(create_indices, created_payments):
final_payments_list[idx] = payment
# 6. Reconstruct and return the final combined recordset
final_payments = self.env['pos.payment']
for payment in final_payments_list:
if payment:
final_payments += payment
return final_payments