mirror of
https://github.com/pretix/pretix.git
synced 2026-05-03 14:54:04 +00:00
Add new field OrderRefund.comment
This commit is contained in:
@@ -502,7 +502,7 @@ class OrderRefundSerializer(I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = OrderRefund
|
||||
fields = ('local_id', 'state', 'source', 'amount', 'payment', 'created', 'execution_date', 'provider')
|
||||
fields = ('local_id', 'state', 'source', 'amount', 'payment', 'created', 'execution_date', 'comment', 'provider')
|
||||
|
||||
|
||||
class OrderURLField(serializers.URLField):
|
||||
@@ -1324,7 +1324,7 @@ class OrderRefundCreateSerializer(I18nAwareModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = OrderRefund
|
||||
fields = ('state', 'source', 'amount', 'payment', 'execution_date', 'provider', 'info')
|
||||
fields = ('state', 'source', 'amount', 'payment', 'execution_date', 'provider', 'info', 'comment')
|
||||
|
||||
def create(self, validated_data):
|
||||
pid = validated_data.pop('payment', None)
|
||||
|
||||
@@ -652,7 +652,7 @@ class PaymentListExporter(ListExporter):
|
||||
|
||||
headers = [
|
||||
_('Event slug'), _('Order'), _('Payment ID'), _('Creation date'), _('Completion date'), _('Status'),
|
||||
_('Status code'), _('Amount'), _('Payment method')
|
||||
_('Status code'), _('Amount'), _('Payment method'), _('Comment')
|
||||
]
|
||||
yield headers
|
||||
|
||||
@@ -674,7 +674,8 @@ class PaymentListExporter(ListExporter):
|
||||
obj.get_state_display(),
|
||||
obj.state,
|
||||
obj.amount * (-1 if isinstance(obj, OrderRefund) else 1),
|
||||
provider_names.get(obj.provider, obj.provider)
|
||||
provider_names.get(obj.provider, obj.provider),
|
||||
obj.comment if isinstance(obj, OrderRefund) else "",
|
||||
]
|
||||
yield row
|
||||
|
||||
|
||||
18
src/pretix/base/migrations/0175_orderrefund_comment.py
Normal file
18
src/pretix/base/migrations/0175_orderrefund_comment.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.0.11 on 2021-01-15 09:21
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('pretixbase', '0174_merge_20201222_1031'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='orderrefund',
|
||||
name='comment',
|
||||
field=models.TextField(null=True),
|
||||
),
|
||||
]
|
||||
@@ -1716,6 +1716,11 @@ class OrderRefund(models.Model):
|
||||
max_length=255,
|
||||
verbose_name=_("Payment provider")
|
||||
)
|
||||
comment = models.TextField(
|
||||
verbose_name=_("Refund reason"),
|
||||
help_text=_('May be shown to the end user or used e.g. as part of a payment reference.'),
|
||||
null=True, blank=True
|
||||
)
|
||||
info = models.TextField(
|
||||
verbose_name=_("Payment information"),
|
||||
null=True, blank=True
|
||||
|
||||
@@ -3,6 +3,7 @@ from decimal import Decimal
|
||||
|
||||
from django.db import transaction
|
||||
from django.db.models import Count, Exists, IntegerField, OuterRef, Subquery
|
||||
from django.utils.translation import gettext
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.decimal import round_decimal
|
||||
@@ -195,7 +196,8 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
|
||||
if auto_refund:
|
||||
_try_auto_refund(o.pk, manual_refund=manual_refund, allow_partial=True,
|
||||
source=OrderRefund.REFUND_SOURCE_ADMIN, refund_as_giftcard=refund_as_giftcard,
|
||||
giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions)
|
||||
giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions,
|
||||
comment=gettext('Event canceled'))
|
||||
finally:
|
||||
if send:
|
||||
_send_mail(o, send_subject, send_message, subevent, refund_amount, user, o.positions.all())
|
||||
@@ -252,7 +254,8 @@ def cancel_event(self, event: Event, subevent: int, auto_refund: bool,
|
||||
if auto_refund:
|
||||
_try_auto_refund(o.pk, manual_refund=manual_refund, allow_partial=True,
|
||||
source=OrderRefund.REFUND_SOURCE_ADMIN, refund_as_giftcard=refund_as_giftcard,
|
||||
giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions)
|
||||
giftcard_expires=giftcard_expires, giftcard_conditions=giftcard_conditions,
|
||||
comment=gettext('Event canceled'))
|
||||
|
||||
if send:
|
||||
_send_mail(o, send_subject, send_message, subevent, refund_amount, user, positions)
|
||||
|
||||
@@ -2034,7 +2034,7 @@ _unset = object()
|
||||
|
||||
|
||||
def _try_auto_refund(order, manual_refund=False, allow_partial=False, source=OrderRefund.REFUND_SOURCE_BUYER,
|
||||
refund_as_giftcard=False, giftcard_expires=_unset, giftcard_conditions=None):
|
||||
refund_as_giftcard=False, giftcard_expires=_unset, giftcard_conditions=None, comment=None):
|
||||
notify_admin = False
|
||||
error = False
|
||||
if isinstance(order, int):
|
||||
@@ -2059,6 +2059,7 @@ def _try_auto_refund(order, manual_refund=False, allow_partial=False, source=Ord
|
||||
order=order,
|
||||
payment=None,
|
||||
source=source,
|
||||
comment=comment,
|
||||
state=OrderRefund.REFUND_STATE_CREATED,
|
||||
execution_date=now(),
|
||||
amount=can_auto_refund_sum,
|
||||
@@ -2096,6 +2097,7 @@ def _try_auto_refund(order, manual_refund=False, allow_partial=False, source=Ord
|
||||
source=source,
|
||||
state=OrderRefund.REFUND_STATE_CREATED,
|
||||
amount=value,
|
||||
comment=comment,
|
||||
provider=p.provider
|
||||
)
|
||||
order.log_action('pretix.event.order.refund.created', {
|
||||
@@ -2125,6 +2127,7 @@ def _try_auto_refund(order, manual_refund=False, allow_partial=False, source=Ord
|
||||
with transaction.atomic():
|
||||
r = order.refunds.create(
|
||||
source=source,
|
||||
comment=comment,
|
||||
state=OrderRefund.REFUND_STATE_CREATED,
|
||||
amount=refund_amount - can_auto_refund_sum,
|
||||
provider='manual'
|
||||
@@ -2149,13 +2152,14 @@ def _try_auto_refund(order, manual_refund=False, allow_partial=False, source=Ord
|
||||
@app.task(base=ProfiledTask, bind=True, max_retries=5, default_retry_delay=1, throws=(OrderError,))
|
||||
@scopes_disabled()
|
||||
def cancel_order(self, order: int, user: int=None, send_mail: bool=True, api_token=None, oauth_application=None,
|
||||
device=None, cancellation_fee=None, try_auto_refund=False, refund_as_giftcard=False):
|
||||
device=None, cancellation_fee=None, try_auto_refund=False, refund_as_giftcard=False, comment=None):
|
||||
try:
|
||||
try:
|
||||
ret = _cancel_order(order, user, send_mail, api_token, device, oauth_application,
|
||||
cancellation_fee)
|
||||
if try_auto_refund:
|
||||
_try_auto_refund(order, refund_as_giftcard=refund_as_giftcard)
|
||||
_try_auto_refund(order, refund_as_giftcard=refund_as_giftcard,
|
||||
comment=comment)
|
||||
return ret
|
||||
except LockTimeoutException:
|
||||
self.retry()
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
{% load rich_text %}
|
||||
{% load safelink %}
|
||||
{% load eventsignal %}
|
||||
{% load l10n %}
|
||||
{% load phone_format %}
|
||||
{% block title %}
|
||||
{% blocktrans trimmed with code=order.code %}
|
||||
@@ -97,7 +98,10 @@
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="start-action" value="do_nothing">
|
||||
<input type="hidden" name="start-mode" value="partial">
|
||||
<input type="hidden" name="start-partial_amount" value="{{ overpaid }}">
|
||||
{% localize off %}
|
||||
<input type="hidden" name="start-partial_amount" value="{{ overpaid|floatformat:2 }}">
|
||||
{% endlocalize %}
|
||||
<input type="hidden" name="comment" value="{% trans "Refund for overpayment" %}">
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans trimmed with amount=overpaid|money:request.event.currency %}
|
||||
This order is currently overpaid by {{ amount }}.
|
||||
@@ -759,11 +763,19 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% if r.html_info %}
|
||||
{% if r.html_info or staff_session or r.comment %}
|
||||
<tr>
|
||||
<td colspan="1"></td>
|
||||
<td colspan="7">
|
||||
{{ r.html_info|safe }}
|
||||
{% if r.comment %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Comment" %}</dt>
|
||||
<dd>{{ r.comment }}</dd>
|
||||
</dl>
|
||||
{% endif %}
|
||||
{% if r.html_info %}
|
||||
{{ r.html_info|safe }}
|
||||
{% endif %}
|
||||
{% if staff_session %}
|
||||
<p>
|
||||
<a href="" class="btn btn-default btn-xs" data-expandrefund
|
||||
@@ -775,17 +787,6 @@
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
{% elif staff_session %}
|
||||
<tr>
|
||||
<td colspan="1"></td>
|
||||
<td colspan="7">
|
||||
<a href="" class="btn btn-default btn-xs" data-expandrefund
|
||||
data-id="{{ r.pk }}">
|
||||
<span class="fa-eye fa fa-fw"></span>
|
||||
{% trans "Inspect" %}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
|
||||
@@ -162,6 +162,13 @@
|
||||
<input type="hidden" name="start-mode" value="{{ start_form.cleaned_data.mode }}">
|
||||
<input type="hidden" name="start-partial_amount" value="{{ partial_amount }}">
|
||||
|
||||
<div class="form-group">
|
||||
<label class="control-label" for="id_comment">{% trans "Refund reason" %}</label>
|
||||
<input type="text" name="comment" class="form-control" title="{% trans "May be shown to the end user or used e.g. as part of a payment reference." %}" id="id_comment"
|
||||
value="{{ comment|default:"" }}">
|
||||
<div class="help-block">{% trans "May be shown to the end user or used e.g. as part of a payment reference." %}</div>
|
||||
</div>
|
||||
|
||||
<div class="row checkout-button-row">
|
||||
<div class="col-md-4">
|
||||
<a class="btn btn-block btn-default btn-lg"
|
||||
|
||||
@@ -5,7 +5,7 @@ import os
|
||||
import re
|
||||
from datetime import datetime, time, timedelta
|
||||
from decimal import Decimal, DecimalException
|
||||
from urllib.parse import urlencode
|
||||
from urllib.parse import quote, urlencode
|
||||
|
||||
import vat_moss.id
|
||||
from django.conf import settings
|
||||
@@ -759,6 +759,7 @@ class OrderRefundView(OrderView):
|
||||
|
||||
def choose_form(self):
|
||||
payments = list(self.order.payments.filter(state=OrderPayment.PAYMENT_STATE_CONFIRMED))
|
||||
comment = self.request.POST.get("comment") or self.request.GET.get("comment") or None
|
||||
if self.start_form.cleaned_data.get('mode') == 'full':
|
||||
full_refund = self.order.payment_refund_sum
|
||||
else:
|
||||
@@ -800,6 +801,7 @@ class OrderRefundView(OrderView):
|
||||
else OrderRefund.REFUND_STATE_CREATED
|
||||
),
|
||||
amount=manual_value,
|
||||
comment=comment,
|
||||
provider='manual'
|
||||
))
|
||||
|
||||
@@ -827,6 +829,7 @@ class OrderRefundView(OrderView):
|
||||
execution_date=now(),
|
||||
amount=giftcard_value,
|
||||
provider='giftcard',
|
||||
comment=comment,
|
||||
info=json.dumps({
|
||||
'gift_card': giftcard.pk
|
||||
})
|
||||
@@ -857,6 +860,7 @@ class OrderRefundView(OrderView):
|
||||
execution_date=now(),
|
||||
amount=offsetting_value,
|
||||
provider='offsetting',
|
||||
comment=comment,
|
||||
info=json.dumps({
|
||||
'orders': [order.code]
|
||||
})
|
||||
@@ -891,6 +895,7 @@ class OrderRefundView(OrderView):
|
||||
source=OrderRefund.REFUND_SOURCE_ADMIN,
|
||||
state=OrderRefund.REFUND_STATE_CREATED,
|
||||
amount=value,
|
||||
comment=comment,
|
||||
provider=p.provider
|
||||
))
|
||||
|
||||
@@ -968,6 +973,7 @@ class OrderRefundView(OrderView):
|
||||
'payments': payments,
|
||||
'remainder': to_refund,
|
||||
'order': self.order,
|
||||
'comment': comment,
|
||||
'giftcard_proposal': giftcard_proposal,
|
||||
'partial_amount': (
|
||||
self.request.POST.get('start-partial_amount') if self.request.method == 'POST'
|
||||
@@ -1098,14 +1104,16 @@ class OrderTransition(OrderView):
|
||||
if self.order.pending_sum < 0:
|
||||
messages.success(self.request, _('The order has been canceled. You can now select how you want to '
|
||||
'transfer the money back to the user.'))
|
||||
return redirect(reverse('control:event.order.refunds.start', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'code': self.order.code
|
||||
}) + '?start-action=do_nothing&start-mode=partial&start-partial_amount={}&giftcard={}'.format(
|
||||
round_decimal(self.order.pending_sum * -1),
|
||||
'true' if self.req and self.req.refund_as_giftcard else 'false'
|
||||
))
|
||||
with language(self.order.locale):
|
||||
return redirect(reverse('control:event.order.refunds.start', kwargs={
|
||||
'event': self.request.event.slug,
|
||||
'organizer': self.request.event.organizer.slug,
|
||||
'code': self.order.code
|
||||
}) + '?start-action=do_nothing&start-mode=partial&start-partial_amount={}&giftcard={}&comment={}'.format(
|
||||
round_decimal(self.order.pending_sum * -1),
|
||||
'true' if self.req and self.req.refund_as_giftcard else 'false',
|
||||
quote(gettext('Order canceled'))
|
||||
))
|
||||
|
||||
messages.success(self.request, _('The order has been canceled.'))
|
||||
elif self.order.status == Order.STATUS_PENDING and to == 'e':
|
||||
|
||||
@@ -22,7 +22,7 @@ def get_refund_export_csv(refund_export: RefundExport):
|
||||
output = StreamWriter(byte_data)
|
||||
|
||||
writer = csv.writer(output)
|
||||
writer.writerow([_("Payer"), "IBAN", "BIC", _("Amount"), _("Currency"), _("Code")])
|
||||
writer.writerow([_("Payer"), "IBAN", "BIC", _("Amount"), _("Currency"), _("Code"), _("Comment")])
|
||||
for row in refund_export.rows_data:
|
||||
bic = ''
|
||||
if row.get('bic'):
|
||||
@@ -39,6 +39,7 @@ def get_refund_export_csv(refund_export: RefundExport):
|
||||
localize(Decimal(row['amount'])),
|
||||
refund_export.currency,
|
||||
row['id'],
|
||||
row.get('comment') or '',
|
||||
])
|
||||
|
||||
filename = _get_filename(refund_export) + ".csv"
|
||||
@@ -68,7 +69,7 @@ def build_sepa_xml(refund_export: RefundExport, account_holder, iban, bic):
|
||||
"IBAN": row["iban"],
|
||||
"amount": int(Decimal(row['amount']) * 100), # in euro-cents
|
||||
"execution_date": datetime.date.today(),
|
||||
"description": f"{_('Refund')} {refund_export.entity_slug} {row['id']}",
|
||||
"description": f"{_('Refund')} {refund_export.entity_slug} {row['id']} {row.get('comment') or ''}".strip()[:140],
|
||||
}
|
||||
if row.get('bic'):
|
||||
try:
|
||||
|
||||
@@ -20,6 +20,7 @@ from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.services.orders import change_payment_provider
|
||||
from pretix.base.services.tasks import TransactionAwareTask
|
||||
from pretix.celery_app import app
|
||||
|
||||
from .models import BankImportJob, BankTransaction
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -602,6 +602,7 @@ def _unite_transaction_rows(transaction_rows):
|
||||
"id": ", ".join(sorted(set(r['id'] for r in rows))),
|
||||
"payer": ", ".join(sorted(set(r['payer'] for r in rows))),
|
||||
"amount": sum(r['amount'] for r in rows),
|
||||
"comment": ", ".join(r['comment'] for r in rows if r.get('comment')) or None,
|
||||
})
|
||||
return united_transactions_rows
|
||||
|
||||
@@ -649,6 +650,7 @@ class RefundExportListView(ListView):
|
||||
transaction_rows.append({
|
||||
"amount": refund.amount,
|
||||
"id": refund.full_id,
|
||||
"comment": refund.comment,
|
||||
**{key: data.get(key) for key in ("payer", "iban", "bic")}
|
||||
})
|
||||
refund.done(user=self.request.user)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import copy
|
||||
import tempfile
|
||||
from collections import OrderedDict, defaultdict
|
||||
from datetime import date, datetime, timedelta, time
|
||||
from datetime import date, datetime, time, timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
import pytz
|
||||
|
||||
@@ -18,7 +18,7 @@ from django.shortcuts import get_object_or_404, redirect
|
||||
from django.utils.decorators import method_decorator
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.timezone import now
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.utils.translation import gettext, gettext_lazy as _
|
||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||
from django.views.generic import TemplateView, View
|
||||
|
||||
@@ -849,7 +849,9 @@ class OrderCancelDo(EventViewMixin, OrderDetailMixin, AsyncAction, View):
|
||||
self.order.log_action('pretix.event.order.refund.requested')
|
||||
return self.success(None)
|
||||
else:
|
||||
return self.do(self.order.pk, cancellation_fee=fee, try_auto_refund=True, refund_as_giftcard=giftcard)
|
||||
comment = gettext('Canceled by customer')
|
||||
return self.do(self.order.pk, cancellation_fee=fee, try_auto_refund=True, refund_as_giftcard=giftcard,
|
||||
comment=comment)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
ctx = super().get_context_data(**kwargs)
|
||||
|
||||
@@ -201,6 +201,7 @@ TEST_REFUNDS_RES = [
|
||||
"source": "admin",
|
||||
"created": "2017-12-01T10:00:00Z",
|
||||
"execution_date": "2017-12-01T10:00:00Z",
|
||||
"comment": None,
|
||||
"provider": "stripe",
|
||||
"state": "done",
|
||||
"amount": "23.00"
|
||||
|
||||
@@ -124,6 +124,7 @@ def test_unite_transaction_rows():
|
||||
'iban': 'DE12345678901234567890',
|
||||
'bic': 'HARKE9000',
|
||||
'id': "ROLLA-R-1",
|
||||
'comment': None,
|
||||
'amount': Decimal("42.23"),
|
||||
},
|
||||
{
|
||||
@@ -131,6 +132,7 @@ def test_unite_transaction_rows():
|
||||
'iban': 'DE111111111111111111111',
|
||||
'bic': 'ikswez2020',
|
||||
'id': "PARTY-R-1",
|
||||
'comment': None,
|
||||
'amount': Decimal("6.50"),
|
||||
}
|
||||
], key=_row_key_func)
|
||||
@@ -143,6 +145,7 @@ def test_unite_transaction_rows():
|
||||
'iban': 'DE12345678901234567890',
|
||||
'bic': 'HARKE9000',
|
||||
'id': "ROLLA-R-1",
|
||||
'comment': None,
|
||||
'amount': Decimal("7.77"),
|
||||
},
|
||||
{
|
||||
@@ -150,6 +153,7 @@ def test_unite_transaction_rows():
|
||||
'iban': 'DE111111111111111111111',
|
||||
'bic': 'ikswez2020',
|
||||
'id': "PARTY-R-2",
|
||||
'comment': None,
|
||||
'amount': Decimal("13.50"),
|
||||
}
|
||||
], key=_row_key_func)
|
||||
@@ -160,6 +164,7 @@ def test_unite_transaction_rows():
|
||||
'iban': 'DE12345678901234567890',
|
||||
'bic': 'HARKE9000',
|
||||
'id': "ROLLA-R-1",
|
||||
'comment': None,
|
||||
'amount': Decimal("50.00"),
|
||||
},
|
||||
{
|
||||
@@ -167,5 +172,6 @@ def test_unite_transaction_rows():
|
||||
'iban': 'DE111111111111111111111',
|
||||
'bic': 'ikswez2020',
|
||||
'id': 'PARTY-R-1, PARTY-R-2',
|
||||
'comment': None,
|
||||
'amount': Decimal('20.00'),
|
||||
}], key=_row_key_func)
|
||||
|
||||
Reference in New Issue
Block a user