From 72de5b7b33afe6cdf36e88054dc76b43da0fce9d Mon Sep 17 00:00:00 2001 From: Aaron Schlitt Date: Mon, 14 Oct 2024 15:49:47 +0200 Subject: [PATCH 1/4] Fix sales channels issue --- pretix_wallet/serializers.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pretix_wallet/serializers.py b/pretix_wallet/serializers.py index 44b2101..428bc9f 100644 --- a/pretix_wallet/serializers.py +++ b/pretix_wallet/serializers.py @@ -58,11 +58,16 @@ def validate_products(self, value): def create(self, validated_data): with transaction.atomic(): wallet = self.context["wallet"] + # create sales channel if it does not exist + if not self.context["event"].organizer.sales_channels.filter(identifier="api.terminal").exists(): + self.context["event"].organizer.sales_channels.create(identifier="api.terminal", label="API Terminal", type="api", ) + sales_channel = self.context["event"].organizer.sales_channels.get(identifier="api.terminal") order = Order(event=self.context["event"], customer=wallet.customer) positions = [] for item in validated_data["products"]: positions.append(OrderPosition(order=order, item=item, price=item.default_price)) order.total = sum([p.price for p in positions]) + order.sales_channel = sales_channel order.save() for p in positions: p.save() From 3b35dace18ed3d00bb2c88558d4b049c7f13dc11 Mon Sep 17 00:00:00 2001 From: Aaron Schlitt Date: Mon, 14 Oct 2024 18:21:55 +0200 Subject: [PATCH 2/4] Fix linter errors --- pretix_wallet/payment.py | 10 ++++++---- pretix_wallet/serializers.py | 2 +- pretix_wallet/templatetags/wallet_tags.py | 1 + pretix_wallet/views.py | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pretix_wallet/payment.py b/pretix_wallet/payment.py index 05248f2..0db822b 100644 --- a/pretix_wallet/payment.py +++ b/pretix_wallet/payment.py @@ -25,10 +25,11 @@ class WalletPaymentProvider(GiftCardPayment): verbose_name = _("Wallet") public_name = _("Wallet") - def payment_form_render(self, request: HttpRequest, total: Decimal, order: Order=None) -> str: - return _("Pay with balance on your wallet. Please note that this is only possible if you already topped up your wallet and the balance is not negative.") + def payment_form_render(self, request: HttpRequest, total: Decimal, order: Order = None) -> str: + return _("Pay with balance on your wallet. Please note that this is only possible " + "if you already topped up your wallet and the balance is not negative.") - def checkout_confirm_render(self, request, order: Order=None, info_data: dict=None) -> str: + def checkout_confirm_render(self, request, order: Order = None, info_data: dict = None) -> str: return _("The payment amount will be deducted from your wallet after you confirm the order.") def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str]: @@ -122,7 +123,8 @@ def payment_prepare(self, request: HttpRequest, payment: OrderPayment) -> Union[ @property def settings_form_fields(self): return OrderedDict(list(super().settings_form_fields.items()) + [ - ('api_key', CharField(label=_("API key"), help_text=_("The API key that the terminal uses to authenticate against the POS api provided by this plugin."))), + ('api_key', CharField(label=_("API key"), help_text=_("The API key that the terminal uses to authenticate against " + "the POS api provided by this plugin."))), ]) @property diff --git a/pretix_wallet/serializers.py b/pretix_wallet/serializers.py index 428bc9f..b6d59ad 100644 --- a/pretix_wallet/serializers.py +++ b/pretix_wallet/serializers.py @@ -3,7 +3,7 @@ from django.db import transaction from pretix.base.models import Item, Order, OrderPosition, GiftCardTransaction from rest_framework.exceptions import ValidationError -from rest_framework.fields import SerializerMethodField, CharField, ListField, DateTimeField, IntegerField, FloatField +from rest_framework.fields import SerializerMethodField, CharField, ListField, DateTimeField, FloatField from rest_framework.serializers import Serializer, ModelSerializer from pretix_wallet.models import CustomerWallet diff --git a/pretix_wallet/templatetags/wallet_tags.py b/pretix_wallet/templatetags/wallet_tags.py index 92cd684..a32f7d5 100644 --- a/pretix_wallet/templatetags/wallet_tags.py +++ b/pretix_wallet/templatetags/wallet_tags.py @@ -3,6 +3,7 @@ register = template.Library() + @register.simple_tag() def organizer_url(organizer, urlname): return build_absolute_uri(organizer, urlname) diff --git a/pretix_wallet/views.py b/pretix_wallet/views.py index f4b2218..ff2fe74 100644 --- a/pretix_wallet/views.py +++ b/pretix_wallet/views.py @@ -4,7 +4,7 @@ from django.views import View from django.views.generic import ListView, TemplateView from django.utils.translation import gettext_lazy as _ -from pretix.base.models import GiftCardTransaction, Item +from pretix.base.models import GiftCardTransaction from pretix.multidomain.urlreverse import build_absolute_uri from pretix.presale.utils import _detect_event from pretix.presale.views.customer import CustomerRequiredMixin From 9de51669b5a9a7e5d664fe355f4581a69eeb065f Mon Sep 17 00:00:00 2001 From: Aaron Schlitt Date: Mon, 14 Oct 2024 18:24:52 +0200 Subject: [PATCH 3/4] Fix more linter issues --- pretix_wallet/auth.py | 12 +- pretix_wallet/migrations/0001_initial.py | 31 +++++- pretix_wallet/models.py | 8 +- pretix_wallet/pagination.py | 38 ++++--- pretix_wallet/payment.py | 136 ++++++++++++++++------- pretix_wallet/serializers.py | 85 +++++++++----- pretix_wallet/urls.py | 35 ++++-- pretix_wallet/utils.py | 13 ++- pretix_wallet/views.py | 62 ++++++++--- 9 files changed, 289 insertions(+), 131 deletions(-) diff --git a/pretix_wallet/auth.py b/pretix_wallet/auth.py index affa9d2..dd11e9e 100644 --- a/pretix_wallet/auth.py +++ b/pretix_wallet/auth.py @@ -14,10 +14,14 @@ class TerminalAuthentication(TokenAuthentication): def authenticate(self, request): self.request = request - request.event = Event.objects.filter( - slug=request.resolver_match.kwargs['event'], - organizer__slug=request.resolver_match.kwargs['organizer'], - ).select_related('organizer').first() + request.event = ( + Event.objects.filter( + slug=request.resolver_match.kwargs["event"], + organizer__slug=request.resolver_match.kwargs["organizer"], + ) + .select_related("organizer") + .first() + ) if not request.event: return False return super().authenticate(request) diff --git a/pretix_wallet/migrations/0001_initial.py b/pretix_wallet/migrations/0001_initial.py index 38411f3..4d0c37a 100644 --- a/pretix_wallet/migrations/0001_initial.py +++ b/pretix_wallet/migrations/0001_initial.py @@ -1,7 +1,7 @@ # Generated by Django 4.2.10 on 2024-02-24 18:00 -from django.db import migrations, models import django.db.models.deletion +from django.db import migrations, models class Migration(migrations.Migration): @@ -9,16 +9,35 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ('pretixbase', '0256_itemvariation_unavail_modes'), + ("pretixbase", "0256_itemvariation_unavail_modes"), ] operations = [ migrations.CreateModel( - name='CustomerWallet', + name="CustomerWallet", fields=[ - ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False)), - ('customer', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='wallet', to='pretixbase.customer')), - ('giftcard', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='wallet', to='pretixbase.giftcard')), + ( + "id", + models.BigAutoField( + auto_created=True, primary_key=True, serialize=False + ), + ), + ( + "customer", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="wallet", + to="pretixbase.customer", + ), + ), + ( + "giftcard", + models.OneToOneField( + on_delete=django.db.models.deletion.CASCADE, + related_name="wallet", + to="pretixbase.giftcard", + ), + ), ], ), ] diff --git a/pretix_wallet/models.py b/pretix_wallet/models.py index 339ca66..0b397de 100644 --- a/pretix_wallet/models.py +++ b/pretix_wallet/models.py @@ -3,5 +3,9 @@ class CustomerWallet(models.Model): - customer = models.OneToOneField(Customer, on_delete=models.CASCADE, related_name='wallet') - giftcard = models.OneToOneField(GiftCard, on_delete=models.CASCADE, related_name='wallet') + customer = models.OneToOneField( + Customer, on_delete=models.CASCADE, related_name="wallet" + ) + giftcard = models.OneToOneField( + GiftCard, on_delete=models.CASCADE, related_name="wallet" + ) diff --git a/pretix_wallet/pagination.py b/pretix_wallet/pagination.py index 9eec052..4a781ac 100644 --- a/pretix_wallet/pagination.py +++ b/pretix_wallet/pagination.py @@ -4,25 +4,29 @@ class CustomPagination(pagination.PageNumberPagination): def get_paginated_response(self, data): - return Response({ - 'links': { - 'next': self.get_next_link(), - 'previous': self.get_previous_link() - }, - 'count': self.page.paginator.count, - 'data': data - }) + return Response( + { + "links": { + "next": self.get_next_link(), + "previous": self.get_previous_link(), + }, + "count": self.page.paginator.count, + "data": data, + } + ) class ProductPagination(pagination.PageNumberPagination): def get_paginated_response(self, data): - return Response({ - 'links': { - 'next': self.get_next_link(), - 'previous': self.get_previous_link() - }, - 'count': self.page.paginator.count, - 'data': { - "products": data, + return Response( + { + "links": { + "next": self.get_next_link(), + "previous": self.get_previous_link(), + }, + "count": self.page.paginator.count, + "data": { + "products": data, + }, } - }) + ) diff --git a/pretix_wallet/payment.py b/pretix_wallet/payment.py index 0db822b..1eaeab9 100644 --- a/pretix_wallet/payment.py +++ b/pretix_wallet/payment.py @@ -1,7 +1,7 @@ +from typing import Any, Dict, Union + from _decimal import Decimal from collections import OrderedDict -from typing import Dict, Any, Union - from django.contrib import messages from django.db import transaction from django.forms import CharField @@ -9,9 +9,9 @@ from django.utils.crypto import get_random_string from django.utils.translation import gettext_lazy as _ from pretix.base.customersso.oidc import oidc_authorize_url -from pretix.base.models import Order, OrderPayment, GiftCard +from pretix.base.models import GiftCard, Order, OrderPayment from pretix.base.models.customers import CustomerSSOProvider -from pretix.base.payment import PaymentException, GiftCardPayment +from pretix.base.payment import GiftCardPayment, PaymentException from pretix.base.services.cart import add_payment_to_cart from pretix.helpers import OF_SELF from pretix.multidomain.urlreverse import build_absolute_uri @@ -25,20 +25,35 @@ class WalletPaymentProvider(GiftCardPayment): verbose_name = _("Wallet") public_name = _("Wallet") - def payment_form_render(self, request: HttpRequest, total: Decimal, order: Order = None) -> str: - return _("Pay with balance on your wallet. Please note that this is only possible " - "if you already topped up your wallet and the balance is not negative.") - - def checkout_confirm_render(self, request, order: Order = None, info_data: dict = None) -> str: - return _("The payment amount will be deducted from your wallet after you confirm the order.") - - def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[bool, str]: + def payment_form_render( + self, request: HttpRequest, total: Decimal, order: Order = None + ) -> str: + return _( + "Pay with balance on your wallet. Please note that this is only possible " + "if you already topped up your wallet and the balance is not negative." + ) + + def checkout_confirm_render( + self, request, order: Order = None, info_data: dict = None + ) -> str: + return _( + "The payment amount will be deducted from your wallet after you confirm the order." + ) + + def checkout_prepare( + self, request: HttpRequest, cart: Dict[str, Any] + ) -> Union[bool, str]: if request.customer: if not request.customer.wallet: messages.error(request, _("You do not have a wallet.")) return False if request.customer.wallet.giftcard.value < 0: - messages.error(request, _("Your wallet has a negative balance. Please top it up or use another payment method.")) + messages.error( + request, + _( + "Your wallet has a negative balance. Please top it up or use another payment method." + ), + ) return False cart_session(request) add_payment_to_cart( @@ -48,36 +63,46 @@ def checkout_prepare(self, request: HttpRequest, cart: Dict[str, Any]) -> Union[ info_data=self._get_payment_info_data(request.customer.wallet), ) return True - return self._redirect_user(request, build_absolute_uri(request.event, "presale:event.checkout", kwargs={"step": "payment"})) + return self._redirect_user( + request, + build_absolute_uri( + request.event, "presale:event.checkout", kwargs={"step": "payment"} + ), + ) def _redirect_user(self, request: HttpRequest, next_url: str): provider = CustomerSSOProvider.objects.last() # taken from pretix.presale.views.customer.SSOLoginView as it does not allow for a custom next_url nonce = get_random_string(32) - request.session[f'pretix_customerauth_{provider.pk}_nonce'] = nonce - request.session[f'pretix_customerauth_{provider.pk}_popup_origin'] = None - request.session[f'pretix_customerauth_{provider.pk}_cross_domain_requested'] = request.GET.get( - "request_cross_domain_customer_auth") == "true" - redirect_uri = build_absolute_uri(request.organizer, 'presale:organizer.customer.login.return', kwargs={ - 'provider': provider.pk - }) - - return oidc_authorize_url(provider, f'{nonce}%{next_url}', redirect_uri) + request.session[f"pretix_customerauth_{provider.pk}_nonce"] = nonce + request.session[f"pretix_customerauth_{provider.pk}_popup_origin"] = None + request.session[f"pretix_customerauth_{provider.pk}_cross_domain_requested"] = ( + request.GET.get("request_cross_domain_customer_auth") == "true" + ) + redirect_uri = build_absolute_uri( + request.organizer, + "presale:organizer.customer.login.return", + kwargs={"provider": provider.pk}, + ) + + return oidc_authorize_url(provider, f"{nonce}%{next_url}", redirect_uri) def _get_payment_info_data(self, wallet: CustomerWallet): return { - 'gift_card': wallet.giftcard.pk, - 'gift_card_secret': wallet.giftcard.secret, - 'user': wallet.customer.name_cached, - 'user_id': wallet.customer.external_identifier, - 'retry': True + "gift_card": wallet.giftcard.pk, + "gift_card_secret": wallet.giftcard.secret, + "user": wallet.customer.name_cached, + "user_id": wallet.customer.external_identifier, + "retry": True, } - def execute_payment(self, request: HttpRequest, payment: OrderPayment, is_early_special_case=False) -> str: + def execute_payment( + self, request: HttpRequest, payment: OrderPayment, is_early_special_case=False + ) -> str: # re-implemented as the original method does not allow for giftcards to have negative balance - gcpk = payment.info_data.get('gift_card') + gcpk = payment.info_data.get("gift_card") if not gcpk: raise PaymentException("Invalid state, should never occur.") try: @@ -87,9 +112,13 @@ def execute_payment(self, request: HttpRequest, payment: OrderPayment, is_early_ except GiftCard.DoesNotExist: raise PaymentException("Invalid state, should never occur.") if gc.currency != self.event.currency: # noqa - just a safeguard - raise PaymentException(_("This gift card does not support this currency.")) + raise PaymentException( + _("This gift card does not support this currency.") + ) if not gc.accepted_by(self.event.organizer): - raise PaymentException(_("This gift card is not accepted by this event organizer.")) + raise PaymentException( + _("This gift card is not accepted by this event organizer.") + ) trans = gc.transactions.create( value=-1 * payment.amount, @@ -97,23 +126,35 @@ def execute_payment(self, request: HttpRequest, payment: OrderPayment, is_early_ payment=payment, acceptor=self.event.organizer, ) - payment.info_data['transaction_id'] = trans.pk - payment.confirm(send_mail=not is_early_special_case, generate_invoice=not is_early_special_case) + payment.info_data["transaction_id"] = trans.pk + payment.confirm( + send_mail=not is_early_special_case, + generate_invoice=not is_early_special_case, + ) except PaymentException as e: - payment.fail(info={'error': str(e)}) + payment.fail(info={"error": str(e)}) raise e - def payment_prepare(self, request: HttpRequest, payment: OrderPayment) -> Union[bool, str, None]: + def payment_prepare( + self, request: HttpRequest, payment: OrderPayment + ) -> Union[bool, str, None]: if request.customer: if not request.customer.wallet: messages.error(request, _("You do not have a wallet.")) return False if request.customer.wallet.giftcard.value < 0: - messages.error(request, _("Your wallet has a negative balance. Please top it up or use another payment method.")) + messages.error( + request, + _( + "Your wallet has a negative balance. Please top it up or use another payment method." + ), + ) return False gc = request.customer.wallet.giftcard if gc not in self.event.organizer.accepted_gift_cards: - raise PaymentException(_("Wallet payments cannot be accepted for this event.")) + raise PaymentException( + _("Wallet payments cannot be accepted for this event.") + ) payment.amount = min(payment.amount, max(gc.value, 0)) payment.info_data = self._get_payment_info_data(request.customer.wallet) payment.save() @@ -122,10 +163,21 @@ def payment_prepare(self, request: HttpRequest, payment: OrderPayment) -> Union[ @property def settings_form_fields(self): - return OrderedDict(list(super().settings_form_fields.items()) + [ - ('api_key', CharField(label=_("API key"), help_text=_("The API key that the terminal uses to authenticate against " - "the POS api provided by this plugin."))), - ]) + return OrderedDict( + list(super().settings_form_fields.items()) + + [ + ( + "api_key", + CharField( + label=_("API key"), + help_text=_( + "The API key that the terminal uses to authenticate against " + "the POS api provided by this plugin." + ), + ), + ), + ] + ) @property def test_mode_message(self) -> str: diff --git a/pretix_wallet/serializers.py b/pretix_wallet/serializers.py index b6d59ad..7c1d813 100644 --- a/pretix_wallet/serializers.py +++ b/pretix_wallet/serializers.py @@ -1,36 +1,47 @@ from datetime import datetime - from django.db import transaction -from pretix.base.models import Item, Order, OrderPosition, GiftCardTransaction +from pretix.base.models import GiftCardTransaction, Item, Order, OrderPosition from rest_framework.exceptions import ValidationError -from rest_framework.fields import SerializerMethodField, CharField, ListField, DateTimeField, FloatField -from rest_framework.serializers import Serializer, ModelSerializer +from rest_framework.fields import ( + CharField, + DateTimeField, + FloatField, + ListField, + SerializerMethodField, +) +from rest_framework.serializers import ModelSerializer, Serializer from pretix_wallet.models import CustomerWallet -from pretix_wallet.utils import link_token_to_wallet, create_customerwallet_if_not_exists, CustomerRelatedField +from pretix_wallet.utils import ( + CustomerRelatedField, + create_customerwallet_if_not_exists, + link_token_to_wallet, +) class ProductSerializer(ModelSerializer): - friendly_name = CharField(source='name') + friendly_name = CharField(source="name") price = SerializerMethodField() class Meta: model = Item - fields = ['id', 'friendly_name', 'price'] + fields = ["id", "friendly_name", "price"] def get_price(self, obj): return int(obj.default_price * 100) class WalletSerializer(ModelSerializer): - token_id = CharField(source='customer.wallet.giftcard.linked_media.first.identifier') - paired_user = CharField(source='customer.name_cached') + token_id = CharField( + source="customer.wallet.giftcard.linked_media.first.identifier" + ) + paired_user = CharField(source="customer.name_cached") balance = SerializerMethodField() - created_at = DateTimeField(source='customer.wallet.giftcard.issuance') + created_at = DateTimeField(source="customer.wallet.giftcard.issuance") class Meta: model = CustomerWallet - fields = ['id', 'token_id', 'created_at', 'balance', 'paired_user'] + fields = ["id", "token_id", "created_at", "balance", "paired_user"] def get_created_at(self, obj): return datetime.now() @@ -59,25 +70,41 @@ def create(self, validated_data): with transaction.atomic(): wallet = self.context["wallet"] # create sales channel if it does not exist - if not self.context["event"].organizer.sales_channels.filter(identifier="api.terminal").exists(): - self.context["event"].organizer.sales_channels.create(identifier="api.terminal", label="API Terminal", type="api", ) - sales_channel = self.context["event"].organizer.sales_channels.get(identifier="api.terminal") + if ( + not self.context["event"] + .organizer.sales_channels.filter(identifier="api.terminal") + .exists() + ): + self.context["event"].organizer.sales_channels.create( + identifier="api.terminal", + label="API Terminal", + type="api", + ) + sales_channel = self.context["event"].organizer.sales_channels.get( + identifier="api.terminal" + ) order = Order(event=self.context["event"], customer=wallet.customer) positions = [] for item in validated_data["products"]: - positions.append(OrderPosition(order=order, item=item, price=item.default_price)) + positions.append( + OrderPosition(order=order, item=item, price=item.default_price) + ) order.total = sum([p.price for p in positions]) order.sales_channel = sales_channel order.save() for p in positions: p.save() - payment = order.payments.create(provider="wallet", amount=order.total, info_data={ - 'gift_card': wallet.giftcard.pk, - 'gift_card_secret': wallet.giftcard.secret, - 'user': wallet.customer.name_cached, - 'user_id': wallet.customer.external_identifier, - 'retry': True - }) + payment = order.payments.create( + provider="wallet", + amount=order.total, + info_data={ + "gift_card": wallet.giftcard.pk, + "gift_card_secret": wallet.giftcard.secret, + "user": wallet.customer.name_cached, + "user_id": wallet.customer.external_identifier, + "retry": True, + }, + ) payment.payment_provider.execute_payment(None, payment) order.create_transactions() return order @@ -90,20 +117,26 @@ class CustomerWalletSerializer(ModelSerializer): class Meta: model = CustomerWallet - fields = ['customer', "initial_balance", "token_id"] + fields = ["customer", "initial_balance", "token_id"] def create(self, validated_data): - wallet, created = create_customerwallet_if_not_exists(self.context["organizer"], validated_data["customer"]) + wallet, created = create_customerwallet_if_not_exists( + self.context["organizer"], validated_data["customer"] + ) if created: if "initial_balance" in validated_data: GiftCardTransaction.objects.create( card=validated_data["customer"].wallet.giftcard, value=validated_data["initial_balance"], acceptor=self.context["organizer"], - text="Transferred balance" + text="Transferred balance", ) if "token_id" in validated_data: - link_token_to_wallet(self.context["organizer"], validated_data["customer"], validated_data["token_id"]) + link_token_to_wallet( + self.context["organizer"], + validated_data["customer"], + validated_data["token_id"], + ) return wallet else: raise ValidationError("Wallet already exists") diff --git a/pretix_wallet/urls.py b/pretix_wallet/urls.py index 10ef7fb..351da1f 100644 --- a/pretix_wallet/urls.py +++ b/pretix_wallet/urls.py @@ -1,19 +1,34 @@ from django.urls import path from pretix.api.urls import event_router, orga_router -from pretix_wallet.views import TransactionListView, ProductViewSet, WalletViewSet, TransactionViewSet, PairingView, \ - RemovePairingView, CustomerCreateWalletViewSet +from pretix_wallet.views import ( + CustomerCreateWalletViewSet, + PairingView, + ProductViewSet, + RemovePairingView, + TransactionListView, + TransactionViewSet, + WalletViewSet, +) -app_name = 'pretix_wallet' +app_name = "pretix_wallet" -event_router.register(r'wallet/pos/terminal', ProductViewSet, basename='terminal') -event_router.register(r'wallet/pos/wallets/token', WalletViewSet, basename='user_wallet') -event_router.register(r'wallet/pos/wallets/token/(?P[^/.]+)/transactions', TransactionViewSet, basename='transactions') +event_router.register(r"wallet/pos/terminal", ProductViewSet, basename="terminal") +event_router.register( + r"wallet/pos/wallets/token", WalletViewSet, basename="user_wallet" +) +event_router.register( + r"wallet/pos/wallets/token/(?P[^/.]+)/transactions", + TransactionViewSet, + basename="transactions", +) -orga_router.register(r"wallet", CustomerCreateWalletViewSet, basename="customer-create-wallet") +orga_router.register( + r"wallet", CustomerCreateWalletViewSet, basename="customer-create-wallet" +) organizer_patterns = [ - path('account/wallet/', TransactionListView.as_view(), name='transactions'), - path('account/wallet/pair//', PairingView.as_view(), name='pair'), - path('account/wallet/unpair/', RemovePairingView.as_view(), name='unpair'), + path("account/wallet/", TransactionListView.as_view(), name="transactions"), + path("account/wallet/pair//", PairingView.as_view(), name="pair"), + path("account/wallet/unpair/", RemovePairingView.as_view(), name="unpair"), ] diff --git a/pretix_wallet/utils.py b/pretix_wallet/utils.py index 225456c..7e23d3e 100644 --- a/pretix_wallet/utils.py +++ b/pretix_wallet/utils.py @@ -1,6 +1,6 @@ from django_scopes import scope from pretix.base.media import NfcUidMediaType -from pretix.base.models import ReusableMedium, GiftCard, Customer +from pretix.base.models import Customer, GiftCard, ReusableMedium from pretix.base.models.giftcards import gen_giftcard_secret from rest_framework.relations import SlugRelatedField @@ -8,15 +8,15 @@ def link_token_to_wallet(organizer, customer, token_id): - medium, created = ReusableMedium.objects.get_or_create(identifier=token_id, - organizer=organizer, - type=NfcUidMediaType.identifier) + medium, created = ReusableMedium.objects.get_or_create( + identifier=token_id, organizer=organizer, type=NfcUidMediaType.identifier + ) customer.wallet.giftcard.linked_media.set([medium]) medium.save() def email_address_to_user_slug(email): - return email.split('@')[0] + return email.split("@")[0] def create_customerwallet_if_not_exists(organizer, customer): @@ -28,7 +28,8 @@ def create_customerwallet_if_not_exists(organizer, customer): issuer=organizer, currency="EUR", conditions=f"Wallet for {customer.name_cached} ({customer.email})", - secret=f"{email_address_to_user_slug(customer.email)}-{gen_giftcard_secret(length=organizer.settings.giftcard_length)}") + secret=f"{email_address_to_user_slug(customer.email)}-{gen_giftcard_secret(length=organizer.settings.giftcard_length)}", + ) wallet = CustomerWallet.objects.create(customer=customer, giftcard=giftcard) created = True return wallet, created diff --git a/pretix_wallet/views.py b/pretix_wallet/views.py index ff2fe74..279684e 100644 --- a/pretix_wallet/views.py +++ b/pretix_wallet/views.py @@ -1,24 +1,32 @@ from django.contrib import messages from django.http import Http404 from django.shortcuts import redirect +from django.utils.translation import gettext_lazy as _ from django.views import View from django.views.generic import ListView, TemplateView -from django.utils.translation import gettext_lazy as _ from pretix.base.models import GiftCardTransaction from pretix.multidomain.urlreverse import build_absolute_uri from pretix.presale.utils import _detect_event from pretix.presale.views.customer import CustomerRequiredMixin -from rest_framework.mixins import RetrieveModelMixin, CreateModelMixin +from rest_framework.mixins import CreateModelMixin, RetrieveModelMixin from rest_framework.response import Response from rest_framework.status import HTTP_201_CREATED -from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet +from rest_framework.viewsets import GenericViewSet, ReadOnlyModelViewSet from pretix_wallet.auth import TerminalAuthentication, TerminalPermission from pretix_wallet.models import CustomerWallet from pretix_wallet.pagination import CustomPagination, ProductPagination -from pretix_wallet.serializers import ProductSerializer, WalletSerializer, TransactionSerializer, \ - CustomerWalletSerializer -from pretix_wallet.utils import link_token_to_wallet, create_customerwallet_if_not_exists, email_address_to_user_slug +from pretix_wallet.serializers import ( + CustomerWalletSerializer, + ProductSerializer, + TransactionSerializer, + WalletSerializer, +) +from pretix_wallet.utils import ( + create_customerwallet_if_not_exists, + email_address_to_user_slug, + link_token_to_wallet, +) class TerminalAuthMixin: @@ -41,9 +49,11 @@ def get_queryset(self): def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) - ctx['wallet'] = self.request.customer.wallet - ctx['transponder_paired'] = self.request.customer.wallet.giftcard.linked_media.exists() - ctx['user_slug'] = email_address_to_user_slug(self.request.customer.email) + ctx["wallet"] = self.request.customer.wallet + ctx["transponder_paired"] = ( + self.request.customer.wallet.giftcard.linked_media.exists() + ) + ctx["user_slug"] = email_address_to_user_slug(self.request.customer.email) return ctx @@ -52,20 +62,32 @@ class PairingView(CustomerRequiredMixin, WalletRequiredMixin, TemplateView): def get_context_data(self, **kwargs): ctx = super().get_context_data(**kwargs) - ctx['already_paired'] = self.request.customer.wallet.giftcard.linked_media.exists() + ctx["already_paired"] = ( + self.request.customer.wallet.giftcard.linked_media.exists() + ) return ctx def post(self, request, *args, **kwargs): - link_token_to_wallet(self.request.organizer, self.request.customer, self.kwargs["token_id"]) + link_token_to_wallet( + self.request.organizer, self.request.customer, self.kwargs["token_id"] + ) messages.success(request, _("Your transponder has been paired succesfully.")) - return redirect(build_absolute_uri(self.request.organizer, "plugins:pretix_wallet:transactions")) + return redirect( + build_absolute_uri( + self.request.organizer, "plugins:pretix_wallet:transactions" + ) + ) class RemovePairingView(CustomerRequiredMixin, WalletRequiredMixin, View): def post(self, request, *args, **kwargs): self.request.customer.wallet.giftcard.linked_media.clear() messages.success(request, _("Your transponder has been unpaired succesfully.")) - return redirect(build_absolute_uri(self.request.organizer, "plugins:pretix_wallet:transactions")) + return redirect( + build_absolute_uri( + self.request.organizer, "plugins:pretix_wallet:transactions" + ) + ) class ProductViewSet(TerminalAuthMixin, ReadOnlyModelViewSet): @@ -80,14 +102,16 @@ def get_queryset(self): class WalletViewSet(TerminalAuthMixin, RetrieveModelMixin, GenericViewSet): serializer_class = WalletSerializer pagination_class = CustomPagination - lookup_url_kwarg = 'token_id' + lookup_url_kwarg = "token_id" def get_queryset(self): return CustomerWallet.objects.all() def get_object(self): try: - return CustomerWallet.objects.get(giftcard__linked_media__identifier=self.kwargs['token_id']) + return CustomerWallet.objects.get( + giftcard__linked_media__identifier=self.kwargs["token_id"] + ) except CustomerWallet.DoesNotExist: raise Http404 @@ -98,9 +122,11 @@ class TransactionViewSet(TerminalAuthMixin, CreateModelMixin, GenericViewSet): def get_serializer_context(self): _detect_event(self.request) context = super().get_serializer_context() - self.wallet = CustomerWallet.objects.get(giftcard__linked_media__identifier=self.kwargs['token_id']) - context['wallet'] = self.wallet - context['event'] = self.request.event + self.wallet = CustomerWallet.objects.get( + giftcard__linked_media__identifier=self.kwargs["token_id"] + ) + context["wallet"] = self.wallet + context["event"] = self.request.event return context def create(self, request, *args, **kwargs): From c6af1abd3ce889739109f33281a263af2ba59252 Mon Sep 17 00:00:00 2001 From: Aaron Schlitt Date: Mon, 14 Oct 2024 18:27:22 +0200 Subject: [PATCH 4/4] Add Markdown files to package to fix errors --- MANIFEST.in | 1 + 1 file changed, 1 insertion(+) diff --git a/MANIFEST.in b/MANIFEST.in index 9d6d65c..47ef081 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,4 +2,5 @@ recursive-include pretix_wallet/static * recursive-include pretix_wallet/templates * recursive-include pretix_wallet/locale * include LICENSE +include *.md exclude .gitlab-ci.yml