some cleanups

This commit is contained in:
Sayyid Hamid Mahdavi 2025-10-23 17:25:15 +03:30
parent 413a5497e4
commit c925100fd6
10 changed files with 269 additions and 68 deletions

View file

@ -0,0 +1,17 @@
# Generated by Django 5.1.7 on 2025-10-23 09:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('gooyal_oauth2', '0006_accesstoken_token_checksum_refreshtoken_token_family_and_more'),
]
operations = [
migrations.RemoveField(
model_name='application',
name='balance',
),
]

View file

@ -21,7 +21,7 @@ class OAUTHLoginRequestForm(forms.ModelForm):
fields = ['agreement']
class AccountUpdateForm(forms.ModelForm):
class Meta:
model = UserModel
fields = ['iban']
# class AccountUpdateForm(forms.ModelForm):
# class Meta:
# model = UserModel
# fields = ['iban']

View file

@ -0,0 +1,25 @@
# Generated by Django 5.1.7 on 2025-10-23 09:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('users', '0006_alter_user_balance'),
]
operations = [
migrations.RemoveField(
model_name='user',
name='balance',
),
migrations.RemoveField(
model_name='user',
name='iban',
),
migrations.RemoveField(
model_name='user',
name='iban_verified',
),
]

View file

@ -13,7 +13,8 @@ from rest_framework import generics
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.gooyal_oauth2.validators import OAuth2Validator
from apps.users.forms import OAUTHLoginRequestForm, AccountUpdateForm
from apps.users.forms import OAUTHLoginRequestForm
# from apps.users.forms import AccountUpdateForm
from apps.users.models import User, OAuthCode
UserModel = get_user_model()
@ -95,7 +96,7 @@ class AccountDetailView(DetailView):
class AccountUpdateView(UpdateView):
model = User
template_name = 'users/account_update.html'
form_class = AccountUpdateForm
# form_class = AccountUpdateForm
def get_success_url(self):
messages.success(self.request, 'عملیات انجام شد.')

View file

@ -1,15 +1,46 @@
import django_filters
from django.db import models
from django.db.models import Q
from .constans import TypeChoices
from .models import Transaction, Wallet
from .models import Transaction
class CategoryUUIDFilter(django_filters.BaseInFilter, django_filters.UUIDFilter):
pass
class UserTransactionCategoryFilter(django_filters.BaseInFilter, django_filters.UUIDFilter):
def filter(self, queryset, value):
request = self.parent.request
user = request.user
return queryset.filter(
Q(payer_wallet__owner_uuid=user.pk,
payer_wallet__owner_type=TypeChoices.USER,
payer_wallet__category_id__in=value,
) |
Q(payee_wallet__owner_uuid=user.pk,
payee_wallet__owner_type=TypeChoices.USER,
payee_wallet__category_id__in=value,
))
class UserTransactionFilter(django_filters.FilterSet):
payer_id = django_filters.UUIDFilter(field_name='payer_wallet__owner_uuid', lookup_expr='iexact')
payee_id = django_filters.UUIDFilter(field_name='payee_wallet__owner_uuid', lookup_expr='iexact')
payer = django_filters.UUIDFilter(field_name='payer_wallet__owner_uuid', lookup_expr='iexact')
payee = django_filters.UUIDFilter(field_name='payee_wallet__owner_uuid', lookup_expr='iexact')
wallets = UserTransactionCategoryFilter(field_name='payee_wallet__category', required=True, lookup_expr='in')
class Meta:
model = Transaction
fields = {
}
class WalletFilter(django_filters.FilterSet):
wallets = CategoryUUIDFilter(field_name='category', required=True, lookup_expr='in')
class Meta:
model = Wallet
fields = {
}

View file

@ -0,0 +1,29 @@
# Generated by Django 5.1.7 on 2025-10-23 09:31
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('wallet', '0011_category_currency'),
]
operations = [
migrations.RemoveField(
model_name='transaction',
name='_payee_id',
),
migrations.RemoveField(
model_name='transaction',
name='_payee_type',
),
migrations.RemoveField(
model_name='transaction',
name='_payer_id',
),
migrations.RemoveField(
model_name='transaction',
name='_payer_type',
),
]

View file

@ -160,6 +160,10 @@ class TransferVerifySerializer(serializers.ModelSerializer):
#### Application
class WalletSerializer(serializers.ModelSerializer):
class Meta:
model = Wallet
fields = ['balance', 'category']
class BalanceSerializer(serializers.ModelSerializer):
class Meta:

View file

@ -8,37 +8,23 @@ app_name = "wallet"
user_urlpatterns = [
path('transactions/', user_views.TransactionListView.as_view(), name='user_transaction_list_page'),
path('transactions/<pk>', user_views.TransactionDetailView.as_view(), name='user_transaction_detail_page'),
path('api/wallet/balance', user_views.CategoryMyWalletBalanceView.as_view(), name='user_wallet_balance_api'),
path('api/transactions/', user_views.CategoryTransactionListView.as_view(), name='transaction_list_api'),
# path('api/wallet/balance', user_views.CategoryMyWalletBalanceView.as_view(), name='user_wallet_balance_api'),
path('api/transactions/', user_views.TransactionListAPIView.as_view(), name='transaction_list_api'),
path('api/user/<category_uuid>/balance', user_views.CategoryMyWalletBalanceView.as_view(), name='user_wallet_balance_api'),
# path('api/user/<category_uuid>/balance', user_views.CategoryMyWalletBalanceView.as_view(), name='user_wallet_balance_api'),
path('api/user/<category_uuid>/transactions/', user_views.CategoryTransactionListView.as_view(), name='transaction_list_api'),
# path('api/transactions/<uuid>', TransactionDetail.as_view(), name='transaction_detail_api'),
# path('api/transactions/<uuid>/pay', TransactionPay.as_view(), name='transaction_pay_api'),
# path('api/transactions/<uuid>/receipt', TransactionReceipt.as_view(), name='transaction_receipt_api'),
# #
# path('api/deposit/', DepositSubmit.as_view(), name='deposit_submit_api'),
# path('api/deposit/<uuid>/verify', DepositVerify.as_view(), name='deposit_verify_api'),
# #
# path('api/withdraw/', WithdrawSubmit.as_view(), name='withdraw_submit_api'),
# path('api/withdraw/<uuid>/verify', WithdrawVerify.as_view(), name='withdraw_verify_api'),
# path('api/get_balance/', application_views.WalletBalanceView.as_view(), name='wallet_balance'),
]
application_urlpatterns = [
path('api/application/balance', application_views.BalanceAPIView.as_view(), name='application_wallet_balance_api'),
path('api/application/user_balance/<uuid>', application_views.UserBalanceAPIView.as_view(), name='application_user_wallet_balance_api'),
path('api/application/', application_views.TransactionListAPIView.as_view(), name='application_transaction_list_api'),
path('api/application/<uuid>/', application_views.TransactionDetailAPIView.as_view(), name='application_transaction_detail'),
path('api/application/wallets', application_views.WalletListAPIView.as_view(), name='application_wallet_balance_api'),
path('api/application/user/<user_uuid>/wallets/', application_views.UserWalletListAPIView.as_view(), name='application_user_wallet_api'),
# path('api/application/', application_views.TransactionListAPIView.as_view(), name='application_transaction_list_api'),
# path('api/application/<uuid>/', application_views.TransactionDetailAPIView.as_view(), name='application_transaction_detail'),
path('api/application/<category_uuid>/balance', application_views.BalanceAPIView.as_view(), name='application_wallet_balance_api'),
path('api/application/<category_uuid>/user/<uuid>/balance', application_views.UserBalanceAPIView.as_view(), name='application_user_wallet_balance_api'),
# path('api/application/<category_uuid>/wallet', application_views.BalanceAPIView.as_view(), name='application_wallet_balance_api'),
# path('api/application/<category_uuid>/user/<user_uuid>/wallet', application_views.UserBalanceAPIView.as_view(), name='application_user_wallet_balance_api'),
path('api/application/<category_uuid>/deposit/', application_views.DepositSubmitAPIView.as_view(), name='application_deposit_submit_api'),
path('api/application/<category_uuid>/deposit/<uuid>/verify', application_views.DepositVerifyAPIView.as_view(), name='application_deposit_verify_api'),
@ -46,8 +32,8 @@ application_urlpatterns = [
path('api/application/<category_uuid>/withdraw/', application_views.WithdrawSubmitAPIView.as_view(), name='application_withdraw_submit_api'),
path('api/application/<category_uuid>/withdraw/<uuid>/verify', application_views.WithdrawVerifyAPIView.as_view(), name='application_withdraw_verify_api'),
path('api/application/<category_uuid>/', application_views.TransactionListAPIView.as_view(), name='application_transaction_list_api'),
path('api/application/<category_uuid>/<uuid>/', application_views.TransactionDetailAPIView.as_view(), name='application_transaction_detail'),
path('api/application/<category_uuid>/', application_views.CategoryTransactionListAPIView.as_view(), name='application_transaction_list_api'),
path('api/application/<category_uuid>/<uuid>/', application_views.CategoryTransactionDetailAPIView.as_view(), name='application_transaction_detail'),
]

View file

@ -1,6 +1,7 @@
import logging
from django.db.models import Q
from django_filters.rest_framework import DjangoFilterBackend
from oauth2_provider.contrib.rest_framework import TokenHasScope, IsAuthenticatedOrTokenHasScope
from rest_framework import generics, permissions, mixins
from rest_framework.exceptions import APIException
@ -10,9 +11,10 @@ from rest_framework.response import Response
from apps.users.models import User
from apps.wallet.constans import TypeChoices, StateChoices
from apps.wallet.filters import WalletFilter, UserTransactionFilter
from apps.wallet.models import Transaction, Category, Wallet
from apps.wallet.serializers import ApplicationDepositSerializer, ApplicationWithdrawSerializer, \
TransactionSerializer, BalanceSerializer
TransactionSerializer, BalanceSerializer, WalletSerializer
from utils.exceptions import UnprocessableEntity
from django.utils.translation import gettext_lazy as _
@ -31,12 +33,14 @@ def get_wallet_category(request: Request):
pass
class BalanceAPIView(generics.RetrieveAPIView):
class WalletListAPIView(generics.ListAPIView):
'''
API for getting specified user or application balance.
'''
permission_classes = [TokenHasScope]
serializer_class = BalanceSerializer
filter_backends = (DjangoFilterBackend,)
filterset_class = WalletFilter
permission_classes = [IsAuthenticatedOrTokenHasScope]
required_scopes = ['wallet.application:get_balance']
def get_object(self):
@ -51,62 +55,140 @@ class BalanceAPIView(generics.RetrieveAPIView):
category=category)
return wallet
def get_queryset(self):
category_uuid = self.kwargs.get('category_uuid')
if category_uuid:
category = get_object_or_404(Category.objects.all(), uuid=category_uuid)
else:
category = None
application = get_application(self.request)
wallet, created = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=category)
return Wallet.objects.filter(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION).all()
class UserBalanceAPIView(generics.RetrieveAPIView):
class UserWalletListAPIView(generics.ListAPIView):
'''
API for getting specified user or application balance.
API for getting specified user wallet.
'''
serializer_class = WalletSerializer
filter_backends = (DjangoFilterBackend,)
filterset_class = WalletFilter
permission_classes = [IsAuthenticatedOrTokenHasScope]
serializer_class = BalanceSerializer
required_scopes = ['wallet.application:get_user_balance']
def get_object(self):
queryset = Wallet.objects.all()
def get_queryset(self):
qs = super().get_queryset()
category_uuid = self.kwargs.get('category_uuid')
user_uuid = self.kwargs.get('user_uuid')
if category_uuid:
category = get_object_or_404(Category.objects.all(), uuid=category_uuid)
else:
category = None
user, created = User.objects.get_or_create(uuid=self.kwargs.get('uuid'))
wallet, created = Wallet.objects.get_or_create(owner_uuid=user_uuid, owner_type=TypeChoices.USER,
category=category)
return qs.filter(owner_uuid=user_uuid, owner_type=TypeChoices.USER).all()
class TransactionDetailAPIView(generics.RetrieveAPIView):
serializer_class = TransactionSerializer
lookup_field = 'uuid'
filter_backends = (DjangoFilterBackend,)
filterset_class = WalletFilter
permission_classes = [TokenHasScope]
required_scopes = ['wallet.application:get_transaction_detail']
queryset = Transaction.objects.all()
def get_queryset(self):
qs = super().get_queryset()
application = get_application(self.request)
return Transaction.objects.filter(Q(application=application) |
Q(payer_wallet__owner_uuid=application.pk,
payer_wallet__owner_type=TypeChoices.APPLICATION,
) |
Q(payee_wallet__owner_uuid=application.pk,
payee_wallet__owner_type=TypeChoices.APPLICATION,
)
).all()
class TransactionListAPIView(generics.ListAPIView):
serializer_class = TransactionSerializer
lookup_field = 'uuid'
filter_backends = (DjangoFilterBackend,)
filterset_class = UserTransactionFilter
permission_classes = [IsAuthenticatedOrTokenHasScope]
required_scopes = ['wallet.application:get_transaction_list']
queryset = Transaction.objects.all()
def get_queryset(self):
qs = super().get_queryset()
application = get_application(self.request)
return qs.filter(Q(application=application) |
Q(payer_wallet__owner_uuid=application.pk,
payer_wallet__owner_type=TypeChoices.APPLICATION) |
Q(payee_wallet__owner_uuid=application.pk,
payee_wallet__owner_type=TypeChoices.APPLICATION,
)
).all()
class CategoryTransactionDetailAPIView(generics.RetrieveAPIView):
permission_classes = [TokenHasScope]
serializer_class = TransactionSerializer
lookup_field = 'uuid'
required_scopes = ['wallet.application:get_transaction_detail']
queryset = Transaction.objects.all()
def get_queryset(self):
qs = super().get_queryset()
category_uuid = self.kwargs.get('category_uuid')
if category_uuid:
category = get_object_or_404(Category.objects.all(), uuid=category_uuid)
else:
category = None
user_uuid = self.kwargs.get('uuid')
user, created = User.objects.get_or_create(uuid=user_uuid)
application = get_application(self.request)
wallet, created = Wallet.objects.get_or_create(owner_uuid=user_uuid, owner_type=TypeChoices.USER,
category=category)
return wallet
class TransactionDetailAPIView(generics.RetrieveAPIView):
permission_classes = [TokenHasScope]
serializer_class = TransactionSerializer
lookup_field = 'uuid'
required_scopes = ['wallet.application:get_transaction_detail']
def get_queryset(self):
# TODO: what about category
application = get_application(self.request)
return Transaction.objects.filter(Q(application=application) |
Q(payer_wallet__owner_uuid=application.pk,
payer_wallet__owner_type=TypeChoices.APPLICATION) |
payer_wallet__owner_type=TypeChoices.APPLICATION,
payer_wallet__category=category) |
Q(payee_wallet__owner_uuid=application.pk,
payee_wallet__owner_type=TypeChoices.APPLICATION)
payee_wallet__owner_type=TypeChoices.APPLICATION,
payee_wallet__category=category)
).all()
class TransactionListAPIView(generics.ListAPIView):
class CategoryTransactionListAPIView(generics.ListAPIView):
permission_classes = [TokenHasScope]
serializer_class = TransactionSerializer
lookup_field = 'uuid'
required_scopes = ['wallet.application:get_transaction_list']
queryset = Transaction.objects.all()
def get_queryset(self):
# TODO: what about category?
qs = super().get_queryset()
category_uuid = self.kwargs.get('category_uuid')
if category_uuid:
category = get_object_or_404(Category.objects.all(), uuid=category_uuid)
else:
category = None
application = get_application(self.request)
return Transaction.objects.filter(Q(application=application) |
Q(payer_wallet__owner_uuid=application.pk,
payer_wallet__owner_type=TypeChoices.APPLICATION) |
Q(payee_wallet__owner_uuid=application.pk,
payee_wallet__owner_type=TypeChoices.APPLICATION)
).all()
return qs.filter(Q(application=application) |
Q(payer_wallet__owner_uuid=application.pk,
payer_wallet__owner_type=TypeChoices.APPLICATION,
payer_wallet__category=category) |
Q(payee_wallet__owner_uuid=application.pk,
payee_wallet__owner_type=TypeChoices.APPLICATION,
payee_wallet__category=category)
).all()
# from application to another entity

View file

@ -249,6 +249,32 @@ class CategoryMyWalletBalanceView(generics.RetrieveAPIView):
# this is application create invoice view
class TransactionListAPIView(generics.ListAPIView):
'''
GET: API for getting list of transactions for authenticated user
POST: API for creating transaction for transferring funds from authenticated user to application owner. (deprecated)
args:
- user: authenticated user
'''
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
serializer_class = TransactionSerializer
required_alternate_scopes = {
"GET": [['wallet.user:transaction_list']],
# "POST": [['wallet.invoice:create']],
}
filter_backends = (DjangoFilterBackend,)
filterset_class = UserTransactionFilter
queryset = Transaction.objects.all()
# TODO: redundant
def get_queryset(self):
user = self.request.user
return Transaction.objects.filter(Q(payee_wallet__owner_uuid=user.uuid) |
Q(payer_wallet__owner_uuid=user.uuid)).all()
class CategoryTransactionListView(generics.ListAPIView):
'''
GET: API for getting list of transactions for authenticated user