forked from CGM_Public/pretix_original
Fix #571 -- Partial payments and refunds
This commit is contained in:
@@ -3,18 +3,20 @@ import textwrap
|
||||
from collections import OrderedDict
|
||||
|
||||
from django import forms
|
||||
from django.http import HttpRequest
|
||||
from django.template.loader import get_template
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from i18nfield.fields import I18nFormField, I18nTextarea
|
||||
from i18nfield.strings import LazyI18nString
|
||||
|
||||
from pretix.base.models import Order
|
||||
from pretix.base.models import OrderPayment
|
||||
from pretix.base.payment import BasePaymentProvider
|
||||
|
||||
|
||||
class BankTransfer(BasePaymentProvider):
|
||||
identifier = 'banktransfer'
|
||||
verbose_name = _('Bank transfer')
|
||||
abort_pending_allowed = True
|
||||
|
||||
@staticmethod
|
||||
def form_field(**kwargs):
|
||||
@@ -65,6 +67,9 @@ class BankTransfer(BasePaymentProvider):
|
||||
def checkout_prepare(self, request, total):
|
||||
return True
|
||||
|
||||
def payment_prepare(self, request: HttpRequest, payment: OrderPayment):
|
||||
return True
|
||||
|
||||
def payment_is_valid_session(self, request):
|
||||
return True
|
||||
|
||||
@@ -81,12 +86,12 @@ class BankTransfer(BasePaymentProvider):
|
||||
}
|
||||
return template.render(ctx)
|
||||
|
||||
def order_pending_render(self, request, order) -> str:
|
||||
def payment_pending_render(self, request: HttpRequest, payment: OrderPayment):
|
||||
template = get_template('pretixplugins/banktransfer/pending.html')
|
||||
ctx = {
|
||||
'event': self.event,
|
||||
'order': order,
|
||||
'code': self._code(order),
|
||||
'code': self._code(payment.order),
|
||||
'order': payment.order,
|
||||
'details': self.settings.get('bank_details', as_type=LazyI18nString),
|
||||
}
|
||||
return template.render(ctx)
|
||||
@@ -102,18 +107,18 @@ class BankTransfer(BasePaymentProvider):
|
||||
'payment_info': payment_info, 'order': order}
|
||||
return template.render(ctx)
|
||||
|
||||
def _code(self, order: Order):
|
||||
def _code(self, order):
|
||||
if self.settings.get('omit_hyphen', as_type=bool):
|
||||
return self.event.slug.upper() + order.code
|
||||
else:
|
||||
return order.full_code
|
||||
|
||||
def shred_payment_info(self, order: Order):
|
||||
if not order.payment_info:
|
||||
def shred_payment_info(self, obj):
|
||||
if not obj.info_data:
|
||||
return
|
||||
d = json.loads(order.payment_info)
|
||||
d = obj.info_data
|
||||
d['reference'] = '█'
|
||||
d['payer'] = '█'
|
||||
d['_shredded'] = True
|
||||
order.payment_info = json.dumps(d)
|
||||
order.save(update_fields=['payment_info'])
|
||||
obj.info = json.dumps(d)
|
||||
obj.save(update_fields=['info'])
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import json
|
||||
import logging
|
||||
import re
|
||||
from decimal import Decimal
|
||||
@@ -10,11 +9,10 @@ from django.db.models import Q
|
||||
from django.utils.translation import ugettext_noop
|
||||
|
||||
from pretix.base.i18n import language
|
||||
from pretix.base.models import Event, Order, Organizer, Quota
|
||||
from pretix.base.models import Event, Order, OrderPayment, Organizer, Quota
|
||||
from pretix.base.services.async import TransactionAwareTask
|
||||
from pretix.base.services.locking import LockTimeoutException
|
||||
from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.services.orders import mark_order_paid
|
||||
from pretix.celery_app import app
|
||||
|
||||
from .models import BankImportJob, BankTransaction
|
||||
@@ -50,7 +48,7 @@ def _handle_transaction(trans: BankTransaction, code: str, event: Event=None, or
|
||||
trans.save()
|
||||
return
|
||||
|
||||
if trans.order.status == Order.STATUS_PAID:
|
||||
if trans.order.status == Order.STATUS_PAID and trans.order.pending_sum <= Decimal('0.00'):
|
||||
trans.state = BankTransaction.STATE_DUPLICATE
|
||||
elif trans.order.status == Order.STATUS_REFUNDED:
|
||||
trans.state = BankTransaction.STATE_ERROR
|
||||
@@ -58,17 +56,23 @@ def _handle_transaction(trans: BankTransaction, code: str, event: Event=None, or
|
||||
elif trans.order.status == Order.STATUS_CANCELED:
|
||||
trans.state = BankTransaction.STATE_ERROR
|
||||
trans.message = ugettext_noop('The order has already been canceled.')
|
||||
elif trans.amount != trans.order.total:
|
||||
trans.state = BankTransaction.STATE_INVALID
|
||||
trans.message = ugettext_noop('The transaction amount is incorrect.')
|
||||
else:
|
||||
p = trans.order.payments.get_or_create(
|
||||
amount=trans.amount,
|
||||
provider='banktransfer',
|
||||
state__in=(OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_PENDING),
|
||||
defaults={
|
||||
'state': OrderPayment.PAYMENT_STATE_CREATED,
|
||||
}
|
||||
)[0]
|
||||
p.info_data = {
|
||||
'reference': trans.reference,
|
||||
'date': trans.date,
|
||||
'payer': trans.payer,
|
||||
'trans_id': trans.pk
|
||||
}
|
||||
try:
|
||||
mark_order_paid(trans.order, provider='banktransfer', info=json.dumps({
|
||||
'reference': trans.reference,
|
||||
'date': trans.date,
|
||||
'payer': trans.payer,
|
||||
'trans_id': trans.pk
|
||||
}))
|
||||
p.confirm()
|
||||
except Quota.QuotaExceededException as e:
|
||||
trans.state = BankTransaction.STATE_ERROR
|
||||
trans.message = str(e)
|
||||
@@ -77,6 +81,10 @@ def _handle_transaction(trans: BankTransaction, code: str, event: Event=None, or
|
||||
trans.message = ugettext_noop('Problem sending email.')
|
||||
else:
|
||||
trans.state = BankTransaction.STATE_VALID
|
||||
trans.order.payments.filter(
|
||||
provider='banktransfer',
|
||||
state__in=(OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_PENDING),
|
||||
).update(state=OrderPayment.PAYMENT_STATE_CANCELED)
|
||||
trans.save()
|
||||
|
||||
|
||||
|
||||
@@ -1,22 +1,5 @@
|
||||
{% load i18n %}
|
||||
|
||||
{% if payment_info and order.status == "p" %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
This order has been paid via bank transfer.
|
||||
{% endblocktrans %}</p>
|
||||
{% elif order.status == "p" %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
This order has been marked as paid via bank transfer manually.
|
||||
{% endblocktrans %}</p>
|
||||
{% elif order.status == "r" %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
This order has been paid via bank transfer and marked as refunded.
|
||||
{% endblocktrans %}</p>
|
||||
{% else %}
|
||||
<p>{% blocktrans trimmed %}
|
||||
This order has been planned to be paid via bank transfer, but no payment has been received yet.
|
||||
{% endblocktrans %}</p>
|
||||
{% endif %}
|
||||
{% if payment_info %}
|
||||
<dl class="dl-horizontal">
|
||||
<dt>{% trans "Payer" %}</dt>
|
||||
|
||||
@@ -14,9 +14,8 @@ from django.utils.timezone import now
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.views.generic import DetailView, ListView, View
|
||||
|
||||
from pretix.base.models import Order, Quota
|
||||
from pretix.base.models import Order, OrderPayment, Quota
|
||||
from pretix.base.services.mail import SendMailException
|
||||
from pretix.base.services.orders import mark_order_paid
|
||||
from pretix.base.settings import SettingsSandbox
|
||||
from pretix.base.templatetags.money import money_filter
|
||||
from pretix.control.permissions import (
|
||||
@@ -66,15 +65,22 @@ class ActionView(View):
|
||||
'message': _('The order has already been canceled.')
|
||||
})
|
||||
|
||||
p = trans.order.payments.get_or_create(
|
||||
amount=trans.amount,
|
||||
provider='banktransfer',
|
||||
state__in=(OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_PENDING),
|
||||
defaults={
|
||||
'state': OrderPayment.PAYMENT_STATE_CREATED,
|
||||
}
|
||||
)[0]
|
||||
p.info_data = {
|
||||
'reference': trans.reference,
|
||||
'date': trans.date,
|
||||
'payer': trans.payer,
|
||||
'trans_id': trans.pk
|
||||
}
|
||||
try:
|
||||
mark_order_paid(trans.order, provider='banktransfer', info=json.dumps({
|
||||
'reference': trans.reference,
|
||||
'date': trans.date,
|
||||
'payer': trans.payer,
|
||||
'trans_id': trans.pk
|
||||
}), count_waitinglist=False)
|
||||
trans.state = BankTransaction.STATE_VALID
|
||||
trans.save()
|
||||
p.confirm(user=self.request.user)
|
||||
except Quota.QuotaExceededException as e:
|
||||
return JsonResponse({
|
||||
'status': 'error',
|
||||
@@ -88,8 +94,12 @@ class ActionView(View):
|
||||
else:
|
||||
trans.state = BankTransaction.STATE_VALID
|
||||
trans.save()
|
||||
trans.order.payments.filter(
|
||||
provider='banktransfer',
|
||||
state__in=(OrderPayment.PAYMENT_STATE_CREATED, OrderPayment.PAYMENT_STATE_PENDING),
|
||||
).update(state=OrderPayment.PAYMENT_STATE_CANCELED)
|
||||
return JsonResponse({
|
||||
'status': 'ok'
|
||||
'status': 'ok',
|
||||
})
|
||||
|
||||
def _assign(self, trans, code):
|
||||
|
||||
Reference in New Issue
Block a user