67 lines
2.7 KiB
Python
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
|