Support for external gift cards (#2912)

This commit is contained in:
Raphael Michel
2022-11-23 14:52:56 +01:00
committed by GitHub
parent d3589696d7
commit 9624b1c505
24 changed files with 1521 additions and 523 deletions

View File

@@ -31,7 +31,7 @@
# Unless required by applicable law or agreed to in writing, software distributed under the Apache License 2.0 is
# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations under the License.
import copy
from collections import defaultdict
from datetime import datetime, timedelta
from decimal import Decimal
@@ -39,9 +39,11 @@ from functools import wraps
from itertools import groupby
from django.conf import settings
from django.contrib import messages
from django.db.models import Exists, OuterRef, Prefetch, Sum
from django.utils.functional import cached_property
from django.utils.timezone import now
from django.utils.translation import gettext_lazy as _
from django_scopes import scopes_disabled
from pretix.base.i18n import language
@@ -50,6 +52,7 @@ from pretix.base.models import (
QuestionAnswer, QuestionOption,
)
from pretix.base.services.cart import get_fees
from pretix.base.templatetags.money import money_filter
from pretix.helpers.cookies import set_cookie_without_samesite
from pretix.multidomain.urlreverse import eventreverse
from pretix.presale.signals import question_form_fields
@@ -103,7 +106,7 @@ class CartMixin:
def invoice_address(self):
return cached_invoice_address(self.request)
def get_cart(self, answers=False, queryset=None, order=None, downloads=False):
def get_cart(self, answers=False, queryset=None, order=None, downloads=False, payments=None):
if queryset is not None:
prefetch = []
if answers:
@@ -196,7 +199,8 @@ class CartMixin:
fees = order.fees.all()
elif positions:
fees = get_fees(
self.request.event, self.request, total, self.invoice_address, self.cart_session.get('payment'),
self.request.event, self.request, total, self.invoice_address,
payments if payments is not None else self.cart_session.get('payments', []),
cartpos
)
else:
@@ -233,6 +237,57 @@ class CartMixin:
'itemcount': sum(c.count for c in positions if not c.addon_to)
}
def current_selected_payments(self, total, warn=False, total_includes_payment_fees=False):
raw_payments = copy.deepcopy(self.cart_session.get('payments', []))
payments = []
total_remaining = total
for p in raw_payments:
# This algorithm of treating min/max values and fees needs to stay in sync between the following
# places in the code base:
# - pretix.base.services.cart.get_fees
# - pretix.base.services.orders._get_fees
# - pretix.presale.views.CartMixin.current_selected_payments
if p.get('min_value') and total_remaining < Decimal(p['min_value']):
if warn:
messages.warning(
self.request,
_('Your selected payment method can only be used for a payment of at least {amount}.').format(
amount=money_filter(Decimal(p['min_value']), self.request.event.currency)
)
)
self._remove_payment(p['id'])
continue
to_pay = total_remaining
if p.get('max_value') and to_pay > Decimal(p['max_value']):
to_pay = min(to_pay, Decimal(p['max_value']))
pprov = self.request.event.get_payment_providers(cached=True).get(p['provider'])
if not pprov:
self._remove_payment(p['id'])
continue
if not total_includes_payment_fees:
fee = pprov.calculate_fee(to_pay)
total_remaining += fee
to_pay += fee
else:
fee = Decimal('0.00')
if p.get('max_value') and to_pay > Decimal(p['max_value']):
to_pay = min(to_pay, Decimal(p['max_value']))
p['payment_amount'] = to_pay
p['provider_name'] = pprov.public_name
p['pprov'] = pprov
p['fee'] = fee
total_remaining -= to_pay
payments.append(p)
return payments
def _remove_payment(self, payment_id):
self.cart_session['payments'] = [p for p in self.cart_session['payments'] if p.get('id') != payment_id]
def cart_exists(request):
from pretix.presale.views.cart import get_or_create_cart_id
@@ -334,7 +389,7 @@ def get_cart_is_free(request):
pos = get_cart(request)
ia = get_cart_invoice_address(request)
total = get_cart_total(request)
fees = get_fees(request.event, request, total, ia, cs.get('payment'), pos)
fees = get_fees(request.event, request, total, ia, cs.get('payments', []), pos)
request._cart_free_cache = total + sum(f.value for f in fees) == Decimal('0.00')
return request._cart_free_cache