change wallet to account

This commit is contained in:
Sayyid Hamid Mahdavi 2025-10-25 14:26:47 +03:30
parent c925100fd6
commit b89487653f
11 changed files with 204 additions and 147 deletions

View file

@ -1,5 +1,5 @@
from django.contrib import admin
from .models import Transaction, Wallet, Category
from .models import Transaction, Account, Category
class TransactionAdmin(admin.ModelAdmin):
list_display = ['uuid', 'amount', 'created_at', 'updated_at', 'payer', 'payer_type', 'payee', 'payee_type', 'state', 'application']
@ -7,5 +7,5 @@ class TransactionAdmin(admin.ModelAdmin):
list_filter = ['state']
admin.site.register(Transaction, TransactionAdmin)
admin.site.register(Wallet)
admin.site.register(Account)
admin.site.register(Category)

View file

@ -3,33 +3,33 @@ from django.db import models
from django.db.models import Q
from .constans import TypeChoices
from .models import Transaction, Wallet
from .models import Transaction, Account
class CategoryUUIDFilter(django_filters.BaseInFilter, django_filters.UUIDFilter):
class WalletUUIDFilter(django_filters.BaseInFilter, django_filters.UUIDFilter):
pass
class UserTransactionCategoryFilter(django_filters.BaseInFilter, django_filters.UUIDFilter):
class UserTransactionWalletFilter(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(payer_account__owner_uuid=user.pk,
payer_account__owner_type=TypeChoices.USER,
payer_account__category_id__in=value,
) |
Q(payee_wallet__owner_uuid=user.pk,
payee_wallet__owner_type=TypeChoices.USER,
payee_wallet__category_id__in=value,
Q(payee_account__owner_uuid=user.pk,
payee_account__owner_type=TypeChoices.USER,
payee_account__category_id__in=value,
))
class UserTransactionFilter(django_filters.FilterSet):
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')
payer = django_filters.UUIDFilter(field_name='payer_account__owner_uuid', lookup_expr='iexact')
payee = django_filters.UUIDFilter(field_name='payee_account__owner_uuid', lookup_expr='iexact')
wallets = UserTransactionWalletFilter(field_name='payee_account__wallet', required=True, lookup_expr='in')
class Meta:
model = Transaction
@ -37,10 +37,10 @@ class UserTransactionFilter(django_filters.FilterSet):
}
class WalletFilter(django_filters.FilterSet):
wallets = CategoryUUIDFilter(field_name='category', required=True, lookup_expr='in')
class AccountFilter(django_filters.FilterSet):
wallets = WalletUUIDFilter(field_name='category', required=True, lookup_expr='in')
class Meta:
model = Wallet
model = Account
fields = {
}

View file

@ -0,0 +1,18 @@
# Generated by Django 5.1.7 on 2025-10-25 10:41
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wallet', '0012_remove_transaction__payee_id_and_more'),
]
operations = [
migrations.RenameModel(
old_name='Wallet',
new_name='Account',
),
]

View file

@ -0,0 +1,24 @@
# Generated by Django 5.1.7 on 2025-10-25 10:42
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wallet', '0013_rename_wallet_account_and_more'),
]
operations = [
migrations.RenameField(
model_name='transaction',
old_name='payee_wallet',
new_name='payee_account',
),
migrations.RenameField(
model_name='transaction',
old_name='payer_wallet',
new_name='payer_account',
),
]

View file

@ -0,0 +1,24 @@
# Generated by Django 5.1.7 on 2025-10-25 10:44
import django.db.models.deletion
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wallet', '0014_remove_transaction_payee_wallet_and_more'),
]
operations = [
migrations.AlterField(
model_name='transaction',
name='payee_account',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='payee_account_transactions', to='wallet.account'),
),
migrations.AlterField(
model_name='transaction',
name='payer_account',
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, related_name='payer_account_transactions', to='wallet.account'),
),
]

View file

@ -22,16 +22,16 @@ class CurrencyChoices(models.TextChoices):
IRANIAN_RIAL = '166ab7ce33b34799950d45035a9997d6', _('IRANIAN RIAL') # uuid without dash
class WalletQuerySet(models.QuerySet):
class AccountQuerySet(models.QuerySet):
pass
class Wallet(BaseModel):
class Account(BaseModel):
owner_uuid = models.UUIDField(db_index=True, null=False)
category = models.ForeignKey('Category', on_delete=models.PROTECT, null=True)
owner_type = models.IntegerField(choices=TypeChoices.choices, db_index=True)
balance = models.BigIntegerField(_('balance'), default=0)
objects = WalletQuerySet.as_manager()
objects = AccountQuerySet.as_manager()
def get_owner(self):
if self.owner_type == TypeChoices.APPLICATION:
@ -85,7 +85,7 @@ class Category(BaseModel):
class TransactionQuerySet(models.QuerySet):
def available(self):
return self.select_related('payer_wallet', 'payee_wallet')
return self.select_related('payer_account', 'payee_account')
class Transaction(BaseModel):
@ -94,11 +94,11 @@ class Transaction(BaseModel):
state = models.IntegerField(choices=StateChoices.choices, default=StateChoices.CREATED)
application = models.ForeignKey(oauth2_settings.APPLICATION_MODEL, on_delete=models.PROTECT,
related_name='transactions', null=True)
payer_wallet = models.ForeignKey(Wallet, on_delete=models.PROTECT, null=True,
related_name='payer_wallet_transactions',
payer_account = models.ForeignKey(Account, on_delete=models.PROTECT, null=True,
related_name='payer_account_transactions',
db_index=True)
payee_wallet = models.ForeignKey(Wallet, on_delete=models.PROTECT, null=True,
related_name='payee_wallet_transactions',
payee_account = models.ForeignKey(Account, on_delete=models.PROTECT, null=True,
related_name='payee_account_transactions',
db_index=True)
details = models.JSONField(null=True, blank=True, default=dict)
@ -119,34 +119,34 @@ class Transaction(BaseModel):
# unique_together = ('application', 'detail_id',)
def get_payer(self):
return self.payer_wallet.get_owner()
return self.payer_account.get_owner()
def get_payee(self):
return self.payee_wallet.get_owner()
return self.payee_account.get_owner()
@cached_property
def payer_wallet_category(self):
return self.payer_wallet and self.payer_wallet.category_id
def payer_wallet(self):
return self.payer_account and self.payer_account.category_id
@cached_property
def payee_wallet_category(self):
return self.payee_wallet and self.payee_wallet.category_id
def payee_wallet(self):
return self.payee_account and self.payee_account.category_id
@cached_property
def payer(self):
return self.payer_wallet.owner_uuid
return self.payer_account.owner_uuid
@cached_property
def payer_type(self):
return self.payer_wallet.owner_type
return self.payer_account.owner_type
@cached_property
def payee(self):
return self.payee_wallet.owner_uuid
return self.payee_account.owner_uuid
@cached_property
def payee_type(self):
return self.payee_wallet.owner_type
return self.payee_account.owner_type
def change_state(self, from_state, to_state, error_message=None, **data):
if self.state == from_state:
@ -162,9 +162,9 @@ class Transaction(BaseModel):
raise APIException(error_message)
def withdraw_from_payer_balance(self):
payer_is_allowed_negative_balance = self.payer_wallet.owner_type == TypeChoices.APPLICATION.value and str(
self.payer_wallet.owner_uuid) in settings.ALLOWED_NEGATIVE_BALANCE_APPLICATIONS
if self.amount > self.payer_wallet.balance and not payer_is_allowed_negative_balance:
payer_is_allowed_negative_balance = self.payer_account.owner_type == TypeChoices.APPLICATION.value and str(
self.payer_account.owner_uuid) in settings.ALLOWED_NEGATIVE_BALANCE_APPLICATIONS
if self.amount > self.payer_account.balance and not payer_is_allowed_negative_balance:
raise UnprocessableEntity('not enough balance')
self.payer_wallet.balance = F('balance') - self.amount
self.payer_wallet.save(update_fields=['balance'])

View file

@ -5,7 +5,7 @@ from rest_framework import serializers
from rest_framework.exceptions import APIException
from .constans import TypeChoices
from .models import Transaction, Wallet
from .models import Transaction, Account
from ..gooyal_oauth2.models import Application
from ..users.models import User
@ -13,8 +13,8 @@ from ..users.models import User
class TransactionSerializer(serializers.ModelSerializer):
payee = serializers.UUIDField(read_only=True)
payee_type = serializers.IntegerField(read_only=True)
payee_wallet = serializers.UUIDField(source='payee_wallet_category', read_only=True)
payer_wallet = serializers.UUIDField(source='payer_wallet_category', read_only=True)
# payee_wallet = serializers.UUIDField(source='payee_wallet_category', read_only=True)
# payer_wallet = serializers.UUIDField(source='payer_wallet_category', read_only=True)
role = serializers.SerializerMethodField()
class Meta:
@ -111,7 +111,7 @@ class WithdrawSerializer(serializers.ModelSerializer):
return transaction
class WalletBalanceSerializer(serializers.ModelSerializer):
class AccountBalanceSerializer(serializers.ModelSerializer):
instance_id = serializers.UUIDField(required=True)
instance_type = serializers.ChoiceField(choices=TypeChoices.choices, required=True)
@ -160,22 +160,18 @@ class TransferVerifySerializer(serializers.ModelSerializer):
#### Application
class WalletSerializer(serializers.ModelSerializer):
class AccountSerializer(serializers.ModelSerializer):
class Meta:
model = Wallet
model = Account
fields = ['balance', 'category']
class BalanceSerializer(serializers.ModelSerializer):
class Meta:
model = Wallet
fields = ['balance', 'category']
class ApplicationDepositSerializer(serializers.ModelSerializer):
uuid = serializers.UUIDField(required=False, validators=[])
payee = serializers.UUIDField(required=True)
payee_type = serializers.IntegerField(required=True)
payee_wallet = serializers.UUIDField(source='payee_wallet_category', required=False) # TODO: required True
payer_wallet = serializers.UUIDField(source='payer_wallet_category', read_only=True)
# payee_wallet = serializers.UUIDField(source='payee_wallet', required=False) # TODO: required True
# payer_wallet = serializers.UUIDField(source='payer_wallet', read_only=True)
amount = serializers.IntegerField(required=True, validators=[MinValueValidator(1)])
# TODO: details as fields
@ -204,8 +200,8 @@ class ApplicationWithdrawSerializer(serializers.ModelSerializer):
uuid = serializers.UUIDField(required=False, validators=[])
payer = serializers.UUIDField(required=True)
payer_type = serializers.IntegerField(required=True)
payer_wallet = serializers.UUIDField(source='payer_wallet_category',required=False) # TODO: required True
payee_wallet = serializers.UUIDField(source='payee_wallet_category', read_only=True) # TODO: required True
# payer_wallet = serializers.UUIDField(source='payer_wallet',required=False) # TODO: required True
# payee_wallet = serializers.UUIDField(source='payee_wallet', read_only=True) # TODO: required True
amount = serializers.IntegerField(required=True, validators=[MinValueValidator(1)])
class Meta:

View file

@ -8,7 +8,7 @@ from rest_framework.test import APITestCase, override_settings
from apps.users.models import User
from apps.wallet.constans import TypeChoices
from apps.wallet.models import Wallet
from apps.wallet.models import Account
from apps.wallet.models import Category
AccessToken = get_access_token_model()
@ -41,9 +41,9 @@ class ApplicationApiFlowsTests(APITestCase):
def setUp(self):
self.application_user, _ = User.objects.get_or_create(pk=self.application_uuid)
self.payer_user, _ = User.objects.get_or_create(pk=self.payer_uuid)
self.application_wallet, _ = Wallet.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300)
self.payee_wallet, _ = Wallet.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER)
self.payer_wallet, _ = Wallet.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300)
self.application_wallet, _ = Account.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300)
self.payee_wallet, _ = Account.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER)
self.payer_wallet, _ = Account.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300)
expire_datetime = timezone.now() + timedelta(seconds=3600)
expire_datetime.isoformat()
@ -77,12 +77,12 @@ class ApplicationApiFlowsTests(APITestCase):
)
self.wallet_category1, _ = Category.objects.get_or_create(application=self.application, uuid=self.wallet_category1_uuid)
self.wallet_category2, _ = Category.objects.get_or_create(application=self.application, uuid=self.wallet_category2_uuid)
self.application_wallet1, _ = Wallet.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300, category=self.wallet_category1)
self.application_wallet2, _ = Wallet.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300, category=self.wallet_category2)
self.payee_wallet1, _ = Wallet.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER, category=self.wallet_category1)
self.payee_wallet2, _ = Wallet.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER, category=self.wallet_category2)
self.payer_wallet1, _ = Wallet.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300, category=self.wallet_category1)
self.payer_wallet2, _ = Wallet.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300, category=self.wallet_category2)
self.application_wallet1, _ = Account.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300, category=self.wallet_category1)
self.application_wallet2, _ = Account.objects.get_or_create(owner_uuid=self.application_uuid, owner_type=TypeChoices.APPLICATION, balance=300, category=self.wallet_category2)
self.payee_wallet1, _ = Account.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER, category=self.wallet_category1)
self.payee_wallet2, _ = Account.objects.get_or_create(owner_uuid=self.payee_uuid, owner_type=TypeChoices.USER, category=self.wallet_category2)
self.payer_wallet1, _ = Account.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300, category=self.wallet_category1)
self.payer_wallet2, _ = Account.objects.get_or_create(owner_uuid=self.payer_uuid, owner_type=TypeChoices.USER, balance=300, category=self.wallet_category2)
def tearDown(self):
super().tearDown()

View file

@ -8,16 +8,16 @@ 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/wallet/balance', user_views.CategoryMyAccountBalanceView.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.CategoryMyAccountBalanceView.as_view(), name='user_wallet_balance_api'),
path('api/user/<category_uuid>/transactions/', user_views.CategoryTransactionListView.as_view(), name='transaction_list_api'),
]
application_urlpatterns = [
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/accounts/', application_views.AccountListAPIView.as_view(), name='application_accounts_balance_api'),
path('api/application/user/<user_uuid>/accounts/', application_views.UserAccountListAPIView.as_view(), name='application_user_account_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'),

View file

@ -11,10 +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.filters import AccountFilter, UserTransactionFilter
from apps.wallet.models import Transaction, Category, Account
from apps.wallet.serializers import ApplicationDepositSerializer, ApplicationWithdrawSerializer, \
TransactionSerializer, BalanceSerializer, WalletSerializer
TransactionSerializer, AccountSerializer
from utils.exceptions import UnprocessableEntity
from django.utils.translation import gettext_lazy as _
@ -29,17 +29,13 @@ def get_application(request):
return application
def get_wallet_category(request: Request):
pass
class WalletListAPIView(generics.ListAPIView):
class AccountListAPIView(generics.ListAPIView):
'''
API for getting specified user or application balance.
'''
serializer_class = BalanceSerializer
serializer_class = AccountSerializer
filter_backends = (DjangoFilterBackend,)
filterset_class = WalletFilter
filterset_class = AccountFilter
permission_classes = [IsAuthenticatedOrTokenHasScope]
required_scopes = ['wallet.application:get_balance']
@ -51,9 +47,9 @@ class WalletListAPIView(generics.ListAPIView):
category = None
application = get_application(self.request)
wallet, created = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
account, created = Account.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=category)
return wallet
return account
def get_queryset(self):
category_uuid = self.kwargs.get('category_uuid')
@ -62,22 +58,22 @@ class WalletListAPIView(generics.ListAPIView):
else:
category = None
application = get_application(self.request)
wallet, created = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
wallet, created = Account.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()
return Account.objects.filter(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION).all()
class UserWalletListAPIView(generics.ListAPIView):
class UserAccountListAPIView(generics.ListAPIView):
'''
API for getting specified user wallet.
'''
serializer_class = WalletSerializer
serializer_class = AccountSerializer
filter_backends = (DjangoFilterBackend,)
filterset_class = WalletFilter
filterset_class = AccountFilter
permission_classes = [IsAuthenticatedOrTokenHasScope]
required_scopes = ['wallet.application:get_user_balance']
queryset = Wallet.objects.all()
queryset = Account.objects.all()
def get_queryset(self):
qs = super().get_queryset()
@ -88,7 +84,7 @@ class UserWalletListAPIView(generics.ListAPIView):
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,
wallet, created = Account.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()
@ -97,7 +93,7 @@ class TransactionDetailAPIView(generics.RetrieveAPIView):
serializer_class = TransactionSerializer
lookup_field = 'uuid'
filter_backends = (DjangoFilterBackend,)
filterset_class = WalletFilter
filterset_class = AccountFilter
permission_classes = [TokenHasScope]
required_scopes = ['wallet.application:get_transaction_detail']
queryset = Transaction.objects.all()
@ -155,12 +151,12 @@ class CategoryTransactionDetailAPIView(generics.RetrieveAPIView):
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__category=category) |
Q(payee_wallet__owner_uuid=application.pk,
payee_wallet__owner_type=TypeChoices.APPLICATION,
payee_wallet__category=category)
Q(payer_account__owner_uuid=application.pk,
payer_account__owner_type=TypeChoices.APPLICATION,
payer_account__category=category) |
Q(payee_account__owner_uuid=application.pk,
payee_account__owner_type=TypeChoices.APPLICATION,
payee_account__category=category)
).all()
@ -182,12 +178,12 @@ class CategoryTransactionListAPIView(generics.ListAPIView):
application = get_application(self.request)
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)
Q(payer_account__owner_uuid=application.pk,
payer_account__owner_type=TypeChoices.APPLICATION,
payer_account__category=category) |
Q(payee_account__owner_uuid=application.pk,
payee_account__owner_type=TypeChoices.APPLICATION,
payee_account__category=category)
).all()
@ -205,9 +201,9 @@ class DepositSubmitAPIView(generics.CreateAPIView):
else:
category = None
application = get_application(self.request)
wallet, created = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
payer_account, created = Account.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=category)
return Transaction.objects.filter(application=application, payer_wallet=wallet).all()
return Transaction.objects.filter(application=application, payer_account=payer_account).all()
def perform_create(self, serializer):
# TODO: get_or_create instead of create if uuid given
@ -216,29 +212,29 @@ class DepositSubmitAPIView(generics.CreateAPIView):
application = get_application(self.request)
logger.debug(f"Application UUID: {application.uuid}")
payee_wallet_category_uuid = serializer.validated_data.pop('payee_wallet_category')
payee_wallet_category_uuid = payee_wallet_category_uuid and str(payee_wallet_category_uuid)
payee_wallet_uuid = serializer.validated_data.pop('payee_wallet')
payee_wallet_uuid = payee_wallet_uuid and str(payee_wallet_uuid)
payer_wallet_category_uuid = self.kwargs.get('category_uuid')
payer_wallet_uuid = self.kwargs.get('wallet_uuid')
if payer_wallet_category_uuid:
payer_wallet_category = get_object_or_404(Category.objects.all(), uuid=payer_wallet_category_uuid)
if payer_wallet_uuid:
payer_wallet = get_object_or_404(Category.objects.all(), uuid=payer_wallet_uuid)
else:
payer_wallet_category = None
payer_wallet = None
payee_wallet_category = get_object_or_404(Category.objects.all(), uuid=payee_wallet_category_uuid)
payee_wallet = get_object_or_404(Category.objects.all(), uuid=payee_wallet_uuid)
if not (payee_wallet_category and payee_wallet_category.currency == payer_wallet_category.currency):
if not (payee_wallet and payee_wallet.currency == payer_wallet.currency):
raise UnprocessableEntity('payer and payee wallet currency not equal')
payee_id = serializer.validated_data.pop('payee')
payee_type = serializer.validated_data.pop('payee_type')
payer_wallet, _ = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=payer_wallet_category)
logger.debug(f"Payer wallet: {payer_wallet.uuid}")
payee_wallet, _ = Wallet.objects.get_or_create(owner_uuid=payee_id, owner_type=payee_type,
category=payee_wallet_category)
logger.debug(f"Payee wallet: {payee_wallet.uuid}")
payer_account, _ = Account.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=payer_wallet)
logger.debug(f"Payer account: {payer_account.uuid}")
payee_account, _ = Account.objects.get_or_create(owner_uuid=payee_id, owner_type=payee_type,
category=payee_wallet)
logger.debug(f"Payee account: {payee_account.uuid}")
uuid = serializer.validated_data.pop('uuid', None)
details = serializer.validated_data.get('details', {})
@ -246,8 +242,8 @@ class DepositSubmitAPIView(generics.CreateAPIView):
logger.debug(f"Transaction UUID: {uuid}, Reference ID: {reference_id}")
transaction_params = {
'application': application,
'payer_wallet': payer_wallet,
'payee_wallet': payee_wallet,
'payer_account': payer_account,
'payee_account': payee_account,
'amount': serializer.validated_data.get('amount'),
}
if uuid:
@ -267,7 +263,6 @@ class DepositSubmitAPIView(generics.CreateAPIView):
if instance.state == StateChoices.PENDING:
return
# TODO: status code 200 if not created before
if created or instance.state == StateChoices.CREATED:
instance.submit()
else:
@ -288,8 +283,8 @@ class DepositVerifyAPIView(generics.RetrieveAPIView):
category = get_object_or_404(Category.objects.all(), uuid=category_uuid)
else:
category = None
wallet = Wallet.objects.get(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION, category=category)
return Transaction.objects.filter(application=application, payer_wallet=wallet).all()
account = Account.objects.get(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION, category=category)
return Transaction.objects.filter(application=application, payer_account=account).all()
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
@ -313,9 +308,9 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
else:
category = None
application = get_application(self.request)
wallet, created = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
payee_account, created = Account.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=category)
return Transaction.objects.filter(application=application, wallet=wallet).all()
return Transaction.objects.filter(application=application, payee_account=payee_account).all()
def perform_create(self, serializer):
# TODO: get_or_create instead of create if uuid given
@ -324,29 +319,29 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
application = get_application(self.request)
logger.debug(f"Application UUID: {application.uuid}")
payer_wallet_category_uuid = serializer.validated_data.pop('payer_wallet_category')
payer_wallet_category_uuid = payer_wallet_category_uuid and str(payer_wallet_category_uuid)
payer_wallet_uuid = serializer.validated_data.pop('payer_wallet')
payer_wallet_uuid = payer_wallet_uuid and str(payer_wallet_uuid)
payee_wallet_category_uuid = self.kwargs.get('category_uuid')
payee_wallet_uuid = self.kwargs.get('category_uuid')
if payee_wallet_category_uuid:
payee_wallet_category = get_object_or_404(Category.objects.all(), uuid=payee_wallet_category_uuid)
if payee_wallet_uuid:
payee_wallet = get_object_or_404(Category.objects.all(), uuid=payee_wallet_uuid)
else:
payee_wallet_category = None
payee_wallet = None
payer_wallet_category = get_object_or_404(Category.objects.all(), uuid=payer_wallet_category_uuid)
payer_wallet = get_object_or_404(Category.objects.all(), uuid=payer_wallet_uuid)
if not (payer_wallet_category and payer_wallet_category.currency == payee_wallet_category.currency):
if not (payer_wallet and payer_wallet.currency == payee_wallet.currency):
raise UnprocessableEntity('payer and payee wallet currency not equal')
payer_id = serializer.validated_data.pop('payer')
payer_type = serializer.validated_data.pop('payer_type')
payee_wallet, _ = Wallet.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=payee_wallet_category)
logger.debug(f"Payee wallet: {payee_wallet.uuid}")
payer_wallet, _ = Wallet.objects.get_or_create(owner_uuid=payer_id, owner_type=payer_type,
category=payer_wallet_category)
logger.debug(f"Payer wallet: {payer_wallet.uuid}")
payee_account, _ = Account.objects.get_or_create(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION,
category=payee_wallet)
logger.debug(f"Payee account: {payee_account.uuid}")
payer_account, _ = Account.objects.get_or_create(owner_uuid=payer_id, owner_type=payer_type,
category=payer_wallet)
logger.debug(f"Payer account: {payer_account.uuid}")
uuid = serializer.validated_data.pop('uuid', None)
@ -355,8 +350,8 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
logger.debug(f"Transaction UUID: {uuid}, Reference ID: {reference_id}")
transaction_params = {
'application': application,
'payer_wallet': payer_wallet,
'payee_wallet': payee_wallet,
'payer_account': payer_account,
'payee_account': payee_account,
'amount': serializer.validated_data.get('amount'),
}
if uuid:
@ -398,8 +393,8 @@ class WithdrawVerifyAPIView(generics.RetrieveAPIView):
category = get_object_or_404(Category.objects.all(), uuid=category_uuid)
else:
category = None
wallet = Wallet.objects.get(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION, category=category)
return Transaction.objects.filter(application=application, payee_wallet=wallet).all()
payee_account = Account.objects.get(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION, category=category)
return Transaction.objects.filter(application=application, payee_wallet=payee_account).all()
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()

View file

@ -13,9 +13,9 @@ from rest_framework.permissions import AllowAny
from rest_framework.response import Response
from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRequirements
from apps.wallet.models import Transaction, Category, Wallet
from apps.wallet.models import Transaction, Category, Account
from apps.wallet.serializers import TransactionSerializer, DepositSerializer, WithdrawSerializer, \
BalanceSerializer
AccountSerializer
from ..constans import StateChoices, TypeChoices
from ..filters import UserTransactionFilter
from ..forms import TransactionActionForm
@ -31,12 +31,12 @@ def get_application(request):
return application
class MyWalletBalanceView(generics.RetrieveAPIView):
class UserAccountBalanceView(generics.RetrieveAPIView):
'''
API for getting authenticated user balance.
'''
permission_classes = [IsAuthenticatedOrTokenHasScope]
serializer_class = BalanceSerializer
serializer_class = AccountSerializer
required_scopes = ['wallet.wallet:get_balance']
def get_object(self):
@ -227,12 +227,12 @@ class TransactionDetailView(UpdateView):
class CategoryMyWalletBalanceView(generics.RetrieveAPIView):
class CategoryMyAccountBalanceView(generics.RetrieveAPIView):
'''
API for getting authenticated user balance.
'''
permission_classes = [IsAuthenticatedOrTokenHasScope]
serializer_class = BalanceSerializer
serializer_class = AccountSerializer
required_scopes = ['wallet.wallet:get_balance']
def get_object(self):
@ -243,7 +243,7 @@ class CategoryMyWalletBalanceView(generics.RetrieveAPIView):
else:
category = None
wallet, created = Wallet.objects.get_or_create(owner_uuid=user.uuid, owner_type=TypeChoices.USER,
wallet, created = Account.objects.get_or_create(owner_uuid=user.uuid, owner_type=TypeChoices.USER,
category=category)
return wallet
@ -301,7 +301,7 @@ class CategoryTransactionListView(generics.ListAPIView):
else:
category = None
wallet, created = Wallet.objects.get_or_create(owner_uuid=user.uuid, owner_type=TypeChoices.USER,
wallet, created = Account.objects.get_or_create(owner_uuid=user.uuid, owner_type=TypeChoices.USER,
category=category)
return Transaction.objects.filter(Q(payee_wallet=wallet) |