forked from CGM_Public/pretix_original
Allow to revert a gift card refund
This commit is contained in:
@@ -64,6 +64,14 @@
|
|||||||
<a href="{% url "control:event.order" event=t.order.event.slug organizer=t.order.event.organizer.slug code=t.order.code %}">
|
<a href="{% url "control:event.order" event=t.order.event.slug organizer=t.order.event.organizer.slug code=t.order.code %}">
|
||||||
{{ t.order.full_code }}
|
{{ t.order.full_code }}
|
||||||
</a>
|
</a>
|
||||||
|
{% if t.value > 0 and t.value <= card.value %}
|
||||||
|
<button type="submit" name="revert" value="{{ t.pk }}"
|
||||||
|
class="btn btn-default btn-xs" data-toggle="tooltip"
|
||||||
|
title="{% trans "Create a payment on the respective order that cancels out with this transaction. The order will then likely be overpaid." %}">
|
||||||
|
<span class="fa fa-repeat"></span>
|
||||||
|
{% trans "Revert" %}
|
||||||
|
</button>
|
||||||
|
{% endif %}
|
||||||
{% else %}
|
{% else %}
|
||||||
<em>{% trans "Manual transaction" %}{% if t.text %}: {{ t.text }}{% endif %}</em>
|
<em>{% trans "Manual transaction" %}{% if t.text %}: {{ t.text }}{% endif %}</em>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -23,11 +23,12 @@ from django.views.generic import (
|
|||||||
from pretix.api.models import WebHook
|
from pretix.api.models import WebHook
|
||||||
from pretix.base.auth import get_auth_backends
|
from pretix.base.auth import get_auth_backends
|
||||||
from pretix.base.models import (
|
from pretix.base.models import (
|
||||||
Device, GiftCard, Organizer, Team, TeamInvite, User,
|
Device, GiftCard, OrderPayment, Organizer, Team, TeamInvite, User,
|
||||||
)
|
)
|
||||||
from pretix.base.models.event import Event, EventMetaProperty, EventMetaValue
|
from pretix.base.models.event import Event, EventMetaProperty, EventMetaValue
|
||||||
from pretix.base.models.giftcards import gen_giftcard_secret
|
from pretix.base.models.giftcards import gen_giftcard_secret
|
||||||
from pretix.base.models.organizer import TeamAPIToken
|
from pretix.base.models.organizer import TeamAPIToken
|
||||||
|
from pretix.base.payment import PaymentException
|
||||||
from pretix.base.services.mail import SendMailException, mail
|
from pretix.base.services.mail import SendMailException, mail
|
||||||
from pretix.control.forms.filter import (
|
from pretix.control.forms.filter import (
|
||||||
EventFilterForm, GiftCardFilterForm, OrganizerFilterForm,
|
EventFilterForm, GiftCardFilterForm, OrganizerFilterForm,
|
||||||
@@ -998,7 +999,36 @@ class GiftCardDetailView(OrganizerDetailViewMixin, OrganizerPermissionRequiredMi
|
|||||||
@transaction.atomic()
|
@transaction.atomic()
|
||||||
def post(self, request, *args, **kwargs):
|
def post(self, request, *args, **kwargs):
|
||||||
self.object = GiftCard.objects.select_for_update().get(pk=self.get_object().pk)
|
self.object = GiftCard.objects.select_for_update().get(pk=self.get_object().pk)
|
||||||
if 'value' in request.POST:
|
if 'revert' in request.POST:
|
||||||
|
t = get_object_or_404(self.object.transactions.all(), pk=request.POST.get('revert'), order__isnull=False)
|
||||||
|
if self.object.value - t.value < Decimal('0.00'):
|
||||||
|
messages.error(request, _('Gift cards are not allowed to have negative values.'))
|
||||||
|
elif t.value > 0:
|
||||||
|
r = t.order.payments.create(
|
||||||
|
order=t.order,
|
||||||
|
state=OrderPayment.PAYMENT_STATE_CREATED,
|
||||||
|
amount=t.value,
|
||||||
|
provider='giftcard',
|
||||||
|
info=json.dumps({
|
||||||
|
'gift_card': self.object.pk,
|
||||||
|
'retry': True,
|
||||||
|
})
|
||||||
|
)
|
||||||
|
try:
|
||||||
|
r.payment_provider.execute_payment(None, r)
|
||||||
|
except PaymentException as e:
|
||||||
|
with transaction.atomic():
|
||||||
|
r.state = OrderPayment.PAYMENT_STATE_FAILED
|
||||||
|
r.save()
|
||||||
|
t.order.log_action('pretix.event.order.payment.failed', {
|
||||||
|
'local_id': r.local_id,
|
||||||
|
'provider': r.provider,
|
||||||
|
'error': str(e)
|
||||||
|
})
|
||||||
|
messages.error(request, _('The transaction could not be reversed.'))
|
||||||
|
else:
|
||||||
|
messages.success(request, _('The transaction has been reversed.'))
|
||||||
|
elif 'value' in request.POST:
|
||||||
try:
|
try:
|
||||||
value = DecimalField(localize=True).to_python(request.POST.get('value'))
|
value = DecimalField(localize=True).to_python(request.POST.get('value'))
|
||||||
except ValidationError:
|
except ValidationError:
|
||||||
|
|||||||
@@ -1,6 +1,12 @@
|
|||||||
import pytest
|
from datetime import timedelta
|
||||||
|
|
||||||
from pretix.base.models import Organizer, Team, User
|
import pytest
|
||||||
|
from django.utils.timezone import now
|
||||||
|
from django_scopes import scopes_disabled
|
||||||
|
|
||||||
|
from pretix.base.models import (
|
||||||
|
Order, OrderPayment, OrderRefund, Organizer, Team, User,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
@@ -83,6 +89,37 @@ def test_card_detail_view_transact(organizer, admin_user, gift_card, client):
|
|||||||
assert gift_card.all_logentries().count() == 1
|
assert gift_card.all_logentries().count() == 1
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.django_db
|
||||||
|
def test_card_detail_view_transact_revert_refund(organizer, admin_user, gift_card, client):
|
||||||
|
with scopes_disabled():
|
||||||
|
event = organizer.events.create(
|
||||||
|
name='Dummy', slug='dummy',
|
||||||
|
date_from=now(), plugins='pretix.plugins.banktransfer,pretix.plugins.stripe,tests.testdummy'
|
||||||
|
)
|
||||||
|
o = Order.objects.create(
|
||||||
|
code='FOO', event=event, email='dummy@dummy.test',
|
||||||
|
status=Order.STATUS_CANCELED,
|
||||||
|
datetime=now(), expires=now() + timedelta(days=10),
|
||||||
|
total=14, locale='en'
|
||||||
|
)
|
||||||
|
o.payments.create(
|
||||||
|
amount=o.total, provider='banktransfer', state=OrderPayment.PAYMENT_STATE_CONFIRMED
|
||||||
|
)
|
||||||
|
r = o.refunds.create(
|
||||||
|
amount=o.total, provider='giftcard', state=OrderRefund.REFUND_STATE_DONE
|
||||||
|
)
|
||||||
|
t = gift_card.transactions.create(value=14, order=o, refund=r)
|
||||||
|
|
||||||
|
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||||
|
r = client.post('/control/organizer/dummy/giftcard/{}/'.format(gift_card.pk), {
|
||||||
|
'revert': str(t.pk)
|
||||||
|
})
|
||||||
|
assert 'alert-success' in r.rendered_content
|
||||||
|
assert gift_card.value == 42
|
||||||
|
o.refresh_from_db()
|
||||||
|
assert o.pending_sum == -14
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.django_db
|
@pytest.mark.django_db
|
||||||
def test_card_detail_view_transact_min_value(organizer, admin_user, gift_card, client):
|
def test_card_detail_view_transact_min_value(organizer, admin_user, gift_card, client):
|
||||||
client.login(email='dummy@dummy.dummy', password='dummy')
|
client.login(email='dummy@dummy.dummy', password='dummy')
|
||||||
|
|||||||
Reference in New Issue
Block a user