forked from CGM_Public/pretix_original
Do not CASCADE-delete vouchers when deleting items or quotas
This commit is contained in:
@@ -174,6 +174,8 @@ def filter_available(qs, channel='web', voucher=None, allow_addons=False):
|
||||
q &= Q(pk=voucher.item_id)
|
||||
elif voucher.quota_id:
|
||||
q &= Q(quotas__in=[voucher.quota_id])
|
||||
else:
|
||||
return qs.none()
|
||||
if not voucher or not voucher.show_hidden_items:
|
||||
q &= Q(hide_without_voucher=False)
|
||||
|
||||
@@ -411,6 +413,7 @@ class Item(LoggedModel):
|
||||
self.event.cache.clear()
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.vouchers.update(item=None, variation=None, quota=None)
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
@@ -655,6 +658,7 @@ class ItemVariation(models.Model):
|
||||
return t
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.vouchers.update(item=None, variation=None, quota=None)
|
||||
super().delete(*args, **kwargs)
|
||||
if self.item:
|
||||
self.item.event.cache.clear()
|
||||
@@ -1275,6 +1279,7 @@ class Quota(LoggedModel):
|
||||
return self.name
|
||||
|
||||
def delete(self, *args, **kwargs):
|
||||
self.vouchers.update(item=None, variation=None, quota=None)
|
||||
super().delete(*args, **kwargs)
|
||||
if self.event:
|
||||
self.event.cache.clear()
|
||||
|
||||
@@ -142,22 +142,26 @@ class Voucher(LoggedModel):
|
||||
item = models.ForeignKey(
|
||||
Item, related_name='vouchers',
|
||||
verbose_name=_("Product"),
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
null=True, blank=True,
|
||||
on_delete=models.PROTECT, # We use a fake version of SET_NULL in Item.delete()
|
||||
help_text=_(
|
||||
"This product is added to the user's cart if the voucher is redeemed."
|
||||
)
|
||||
)
|
||||
variation = models.ForeignKey(
|
||||
ItemVariation, related_name='vouchers',
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
null=True, blank=True,
|
||||
on_delete=models.PROTECT, # We use a fake version of SET_NULL in ItemVariation.delete() to avoid the semantic change
|
||||
# that would happen if we just set variation to None
|
||||
verbose_name=_("Product variation"),
|
||||
help_text=_(
|
||||
"This variation of the product select above is being used."
|
||||
)
|
||||
)
|
||||
quota = models.ForeignKey(
|
||||
Quota, related_name='quota',
|
||||
null=True, blank=True, on_delete=models.CASCADE,
|
||||
Quota, related_name='vouchers',
|
||||
null=True, blank=True,
|
||||
on_delete=models.PROTECT, # We use a fake version of SET_NULL in Quota.delete()
|
||||
verbose_name=_("Quota"),
|
||||
help_text=_(
|
||||
"If enabled, the voucher is valid for any product affected by this quota."
|
||||
@@ -408,4 +412,7 @@ class Voucher(LoggedModel):
|
||||
kwargs['subevent'] = self.subevent
|
||||
if self.quota_id:
|
||||
return SeatCategoryMapping.objects.filter(product__quotas__pk=self.quota_id, **kwargs).exists()
|
||||
return self.item.seat_category_mappings.filter(**kwargs).exists()
|
||||
elif self.item_id:
|
||||
return self.item.seat_category_mappings.filter(**kwargs).exists()
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -17,6 +17,19 @@
|
||||
{% csrf_token %}
|
||||
{% if possible %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the product <strong>{{ item }}</strong>?{% endblocktrans %}</p>
|
||||
{% if vouchers %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed count count=vouchers %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% plural %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% endblocktrans %}
|
||||
<a href="{% url "control:event.vouchers" organizer=request.organizer.slug event=request.event.slug %}?itemvar={{ item.pk }}"
|
||||
class="btn btn-default">
|
||||
{% trans "Show affected vouchers" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<p>{% blocktrans %}You cannot delete the product <strong>{{ item }}</strong> because it already has been ordered, but you can deactivate it.{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
|
||||
@@ -3,23 +3,42 @@
|
||||
{% load bootstrap3 %}
|
||||
{% block title %}{% trans "Delete quota" %}{% endblock %}
|
||||
{% block inside %}
|
||||
<h1>{% trans "Delete quota" %}</h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the quota <strong>{{ quota }}</strong>?{% endblocktrans %}</p>
|
||||
{% if dependent|length > 0 %}
|
||||
<p>{% blocktrans %}The following products might be no longer available for sale:{% endblocktrans %}</p>
|
||||
{% for item in dependent %}
|
||||
<li><a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a></li>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<h1>{% trans "Delete quota" %}</h1>
|
||||
<form action="" method="post" class="form-horizontal">
|
||||
{% csrf_token %}
|
||||
<p>{% blocktrans %}Are you sure you want to delete the quota <strong>{{ quota }}</strong>?{% endblocktrans %}</p>
|
||||
{% if dependent|length > 0 %}
|
||||
<div class="alert alert-info">
|
||||
<p>{% blocktrans %}The following products might be no longer available for sale:{% endblocktrans %}</p>
|
||||
<ul>
|
||||
{% for item in dependent %}
|
||||
<li>
|
||||
<a href="{% url "control:event.item" organizer=request.event.organizer.slug event=request.event.slug item=item.pk %}">{{ item.name }}</a>
|
||||
</li>
|
||||
{% endfor %}
|
||||
</ul>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if vouchers %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed count count=vouchers %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% plural %}
|
||||
That will cause {{ count }} voucher to be unusable.
|
||||
{% endblocktrans %}
|
||||
<a href="{% url "control:event.vouchers" organizer=request.organizer.slug event=request.event.slug %}?itemvar=q-{{ quota.pk }}"
|
||||
class="btn btn-default">
|
||||
{% trans "Show affected vouchers" %}
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="form-group submit-group">
|
||||
<a href="{% url "control:event.items.quotas" organizer=request.event.organizer.slug event=request.event.slug %}" class="btn btn-default btn-cancel">
|
||||
{% trans "Cancel" %}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-danger btn-save">
|
||||
{% trans "Delete" %}
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</form>
|
||||
{% endblock %}
|
||||
|
||||
@@ -128,7 +128,7 @@
|
||||
{% if v.variation %}
|
||||
– {{ v.variation }}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% elif v.quota %}
|
||||
{% blocktrans trimmed with quota=v.quota.name %}
|
||||
Any product in quota "{{ quota }}"
|
||||
{% endblocktrans %}
|
||||
|
||||
@@ -771,7 +771,8 @@ class QuotaDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['dependent'] = list(self.get_object().items.all())
|
||||
context['dependent'] = list(self.object.items.all())
|
||||
context['vouchers'] = self.object.vouchers.count()
|
||||
return context
|
||||
|
||||
@transaction.atomic
|
||||
@@ -1183,6 +1184,7 @@ class ItemDelete(EventPermissionRequiredMixin, DeleteView):
|
||||
def get_context_data(self, *args, **kwargs) -> dict:
|
||||
context = super().get_context_data(*args, **kwargs)
|
||||
context['possible'] = self.is_allowed()
|
||||
context['vouchers'] = self.object.vouchers.count()
|
||||
return context
|
||||
|
||||
def is_allowed(self) -> bool:
|
||||
|
||||
Reference in New Issue
Block a user