mirror of
https://gitlab.crans.org/bde/nk20
synced 2024-11-26 18:37:12 +00:00
🎉 Use select_for_update tag to update note balances when we save a Transaction to avoid concurrency issues
This commit is contained in:
parent
242b85676d
commit
d4090a4043
@ -2,6 +2,7 @@
|
|||||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
from django.core.exceptions import ValidationError
|
from django.core.exceptions import ValidationError
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction
|
||||||
|
from django.db.models import F
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.utils.translation import gettext_lazy as _
|
from django.utils.translation import gettext_lazy as _
|
||||||
@ -208,7 +209,15 @@ class Transaction(PolymorphicModel):
|
|||||||
"""
|
"""
|
||||||
When saving, also transfer money between two notes
|
When saving, also transfer money between two notes
|
||||||
"""
|
"""
|
||||||
with transaction.atomic():
|
if self.source.pk == self.destination.pk:
|
||||||
|
# When source == destination, no money is transferred and no transaction is created
|
||||||
|
return
|
||||||
|
|
||||||
|
# We refresh the notes with the "select for update" tag to avoid concurrency issues
|
||||||
|
self.source = Note.objects.filter(pk=self.source_id).select_for_update().get()
|
||||||
|
self.destination = Note.objects.filter(pk=self.destination_id).select_for_update().get()
|
||||||
|
|
||||||
|
# Check that the amounts stay between big integer bounds
|
||||||
diff_source, diff_dest = self.validate()
|
diff_source, diff_dest = self.validate()
|
||||||
|
|
||||||
if not self.source.is_active or not self.destination.is_active:
|
if not self.source.is_active or not self.destination.is_active:
|
||||||
@ -224,21 +233,13 @@ class Transaction(PolymorphicModel):
|
|||||||
if not self.destination_alias:
|
if not self.destination_alias:
|
||||||
self.destination_alias = str(self.destination)
|
self.destination_alias = str(self.destination)
|
||||||
|
|
||||||
if self.source.pk == self.destination.pk:
|
|
||||||
# When source == destination, no money is transferred and no transaction is created
|
|
||||||
return
|
|
||||||
|
|
||||||
# We save first the transaction, in case of the user has no right to transfer money
|
# We save first the transaction, in case of the user has no right to transfer money
|
||||||
super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
# Save notes
|
# Save notes
|
||||||
self.source.refresh_from_db()
|
|
||||||
self.source.balance += diff_source
|
self.source.balance += diff_source
|
||||||
self.source._force_save = True
|
|
||||||
self.source.save()
|
self.source.save()
|
||||||
self.destination.refresh_from_db()
|
|
||||||
self.destination.balance += diff_dest
|
self.destination.balance += diff_dest
|
||||||
self.destination._force_save = True
|
|
||||||
self.destination.save()
|
self.destination.save()
|
||||||
|
|
||||||
def delete(self, **kwargs):
|
def delete(self, **kwargs):
|
||||||
|
Loading…
Reference in New Issue
Block a user