forked from CGM_Public/pretix_original
CartManager: Fix TransactionManagementError
Bug occured when extending a product and deleting it at the same time
This commit is contained in:
@@ -1078,6 +1078,7 @@ class CartManager:
|
|||||||
quotas_ok = _get_quota_availability(self._quota_diff, self.now_dt)
|
quotas_ok = _get_quota_availability(self._quota_diff, self.now_dt)
|
||||||
err = None
|
err = None
|
||||||
new_cart_positions = []
|
new_cart_positions = []
|
||||||
|
deleted_positions = set()
|
||||||
|
|
||||||
err = err or self._check_min_max_per_product()
|
err = err or self._check_min_max_per_product()
|
||||||
|
|
||||||
@@ -1089,7 +1090,10 @@ class CartManager:
|
|||||||
if op.position.expires > self.now_dt:
|
if op.position.expires > self.now_dt:
|
||||||
for q in op.position.quotas:
|
for q in op.position.quotas:
|
||||||
quotas_ok[q] += 1
|
quotas_ok[q] += 1
|
||||||
op.position.addons.all().delete()
|
addons = op.position.addons.all()
|
||||||
|
deleted_positions |= {a.pk for a in addons}
|
||||||
|
addons.delete()
|
||||||
|
deleted_positions.add(op.position.pk)
|
||||||
op.position.delete()
|
op.position.delete()
|
||||||
|
|
||||||
elif isinstance(op, (self.AddOperation, self.ExtendOperation)):
|
elif isinstance(op, (self.AddOperation, self.ExtendOperation)):
|
||||||
@@ -1239,20 +1243,28 @@ class CartManager:
|
|||||||
if op.seat and not op.seat.is_available(ignore_cart=op.position, sales_channel=self._sales_channel,
|
if op.seat and not op.seat.is_available(ignore_cart=op.position, sales_channel=self._sales_channel,
|
||||||
ignore_voucher_id=op.position.voucher_id):
|
ignore_voucher_id=op.position.voucher_id):
|
||||||
err = err or error_messages['seat_unavailable']
|
err = err or error_messages['seat_unavailable']
|
||||||
op.position.addons.all().delete()
|
|
||||||
|
addons = op.position.addons.all()
|
||||||
|
deleted_positions |= {a.pk for a in addons}
|
||||||
|
deleted_positions.add(op.position.pk)
|
||||||
|
addons.delete()
|
||||||
op.position.delete()
|
op.position.delete()
|
||||||
elif available_count == 1:
|
elif available_count == 1:
|
||||||
op.position.expires = self._expiry
|
op.position.expires = self._expiry
|
||||||
op.position.listed_price = op.listed_price
|
op.position.listed_price = op.listed_price
|
||||||
op.position.price_after_voucher = op.price_after_voucher
|
op.position.price_after_voucher = op.price_after_voucher
|
||||||
# op.position.price will be updated by recompute_final_prices_and_taxes()
|
# op.position.price will be updated by recompute_final_prices_and_taxes()
|
||||||
try:
|
if op.position.pk not in deleted_positions:
|
||||||
op.position.save(force_update=True, update_fields=['expires', 'listed_price', 'price_after_voucher'])
|
try:
|
||||||
except DatabaseError:
|
op.position.save(force_update=True, update_fields=['expires', 'listed_price', 'price_after_voucher'])
|
||||||
# Best effort... The position might have been deleted in the meantime!
|
except DatabaseError:
|
||||||
pass
|
# Best effort... The position might have been deleted in the meantime!
|
||||||
|
pass
|
||||||
elif available_count == 0:
|
elif available_count == 0:
|
||||||
op.position.addons.all().delete()
|
addons = op.position.addons.all()
|
||||||
|
deleted_positions |= {a.pk for a in addons}
|
||||||
|
deleted_positions.add(op.position.pk)
|
||||||
|
addons.delete()
|
||||||
op.position.delete()
|
op.position.delete()
|
||||||
else:
|
else:
|
||||||
raise AssertionError("ExtendOperation cannot affect more than one item")
|
raise AssertionError("ExtendOperation cannot affect more than one item")
|
||||||
|
|||||||
@@ -2414,6 +2414,25 @@ class CartAddonTest(CartTestMixin, TestCase):
|
|||||||
assert cp2.item == self.workshop1
|
assert cp2.item == self.workshop1
|
||||||
assert cp2.price == 0
|
assert cp2.price == 0
|
||||||
|
|
||||||
|
@classscope(attr='orga')
|
||||||
|
def test_extend_included_addon_no_longer_available(self):
|
||||||
|
self.addon1.price_included = True
|
||||||
|
self.addon1.save()
|
||||||
|
self.quota_tickets.size = 0
|
||||||
|
self.quota_tickets.save()
|
||||||
|
cp1 = CartPosition.objects.create(
|
||||||
|
expires=now() - timedelta(minutes=10), item=self.ticket, price=Decimal('23.00'),
|
||||||
|
event=self.event, cart_id=self.session_key
|
||||||
|
)
|
||||||
|
CartPosition.objects.create(
|
||||||
|
expires=now() - timedelta(minutes=10), item=self.workshop1, price=Decimal('0.00'),
|
||||||
|
event=self.event, cart_id=self.session_key, addon_to=cp1
|
||||||
|
)
|
||||||
|
self.cm.extend_expired_positions()
|
||||||
|
with self.assertRaises(CartError):
|
||||||
|
self.cm.commit()
|
||||||
|
assert CartPosition.objects.count() == 0
|
||||||
|
|
||||||
@classscope(attr='orga')
|
@classscope(attr='orga')
|
||||||
def test_cart_addon_remove_parent(self):
|
def test_cart_addon_remove_parent(self):
|
||||||
self.addon1.price_included = True
|
self.addon1.price_included = True
|
||||||
|
|||||||
Reference in New Issue
Block a user