fix(wallet): adapt submit and verify process to new wallet, account concept

adapt submit and verify process to new wallet, account concept

test_withdraw_flow_success
This commit is contained in:
Haydar Ghasemi 2025-10-28 10:54:44 +03:30
parent 821bad13e7
commit 65c9c62484
4 changed files with 54 additions and 67 deletions

View file

@ -200,8 +200,8 @@ class ApplicationWithdrawSerializer(serializers.ModelSerializer):
uuid = serializers.UUIDField(required=False, validators=[]) uuid = serializers.UUIDField(required=False, validators=[])
payer = serializers.UUIDField(required=True) payer = serializers.UUIDField(required=True)
payer_type = serializers.IntegerField(required=True) payer_type = serializers.IntegerField(required=True)
# payer_wallet = serializers.UUIDField(source='payer_wallet',required=False) # TODO: required True payee_wallet = serializers.UUIDField(read_only=True)
# payee_wallet = serializers.UUIDField(source='payee_wallet', read_only=True) # TODO: required True payer_wallet = serializers.UUIDField(required=True)
amount = serializers.IntegerField(required=True, validators=[MinValueValidator(1)]) amount = serializers.IntegerField(required=True, validators=[MinValueValidator(1)])
class Meta: class Meta:

View file

@ -130,7 +130,7 @@ class ApplicationApiFlowsTests(APITestCase):
from_wallet = response.json()['results'][0] from_wallet = response.json()['results'][0]
self.assertEqual(from_wallet['balance'], 300) self.assertEqual(from_wallet['balance'], 300)
params = { params = {
'user': self.payee_uuid, 'owner': self.payee_uuid,
} }
response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertGreater(response.json()['count'], 1) self.assertGreater(response.json()['count'], 1)
@ -166,7 +166,7 @@ class ApplicationApiFlowsTests(APITestCase):
self.assertEqual(from_wallet['balance'], 200) self.assertEqual(from_wallet['balance'], 200)
params = { params = {
'user': self.payee_uuid, 'owner': self.payee_uuid,
} }
response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertGreater(response.json()['count'], 1) self.assertGreater(response.json()['count'], 1)
@ -184,7 +184,7 @@ class ApplicationApiFlowsTests(APITestCase):
from_wallet = response.json()['results'][0] from_wallet = response.json()['results'][0]
self.assertEqual(from_wallet['balance'], 300) self.assertEqual(from_wallet['balance'], 300)
params = { params = {
'user': self.payee_uuid, 'owner': self.payee_uuid,
} }
response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
@ -217,7 +217,7 @@ class ApplicationApiFlowsTests(APITestCase):
from_wallet = response.json()['results'][0] from_wallet = response.json()['results'][0]
self.assertEqual(from_wallet['balance'], 300) self.assertEqual(from_wallet['balance'], 300)
params = { params = {
'user': self.payee_uuid, 'owner': self.payee_uuid,
} }
response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertGreater(response.json()['count'], 1) self.assertGreater(response.json()['count'], 1)
@ -282,7 +282,7 @@ class ApplicationApiFlowsTests(APITestCase):
from_wallet = response.json()['results'][0] from_wallet = response.json()['results'][0]
self.assertEqual(from_wallet['balance'], 300) self.assertEqual(from_wallet['balance'], 300)
params = { params = {
'user': self.payee_uuid, 'owner': self.payee_uuid,
} }
response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertGreater(response.json()['count'], 1) self.assertGreater(response.json()['count'], 1)
@ -309,53 +309,56 @@ class ApplicationApiFlowsTests(APITestCase):
auth = self._create_authorization_header(self.payer_access_token.token) auth = self._create_authorization_header(self.payer_access_token.token)
# Checking wallets initials values(application balance = 300 and payee balance = zero) # Checking wallets initials values(application balance = 300 and payee balance = zero)
response = self.client.get(reverse('wallet:application_account_balance_api'), HTTP_AUTHORIZATION=auth) wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex]
self.assertContains(response, 'balance') response = self.client.get(reverse('wallet:application_account_balance_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertEqual(response.json()['balance'], 300) self.assertGreater(response.json()['count'], 1)
from_wallet = response.json()['results'][0]
self.assertEqual(from_wallet['balance'], 300)
params = { params = {
'uuid': self.payer_uuid, 'owner': self.payer_uuid,
'wallet_uuid': self.wallet_rial_uuid,
} }
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertContains(response, 'balance') self.assertGreater(response.json()['count'], 1)
self.assertEqual(response.json()['balance'], 300) to_wallet = response.json()['results'][0]
self.assertEqual(to_wallet['balance'], 300)
# Deposit process # Deposit process
data = { data = {
'amount': 100, 'amount': 100,
'payer': self.payer_uuid, 'payer': self.payer_uuid,
'payer_type': TypeChoices.USER, 'payer_type': TypeChoices.USER,
'payer_account': self.wallet_rial_uuid, 'payer_wallet': self.wallet_rial_uuid,
} }
kwargs_wallet_uuid = { kwargs_payee_wallet = {
'wallet_uuid': self.wallet_rial_uuid, 'payee_wallet': self.wallet_rial_uuid,
} }
response = self.client.post(reverse('wallet:application_withdraw_submit_api', kwargs=kwargs_wallet_uuid), data=data, HTTP_AUTHORIZATION=auth) response = self.client.post(reverse('wallet:application_withdraw_submit_api', kwargs=kwargs_payee_wallet), data=data, HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 201) self.assertEqual(response.status_code, 201)
json_response = response.json() json_response = response.json()
params = { kwargs_payee_wallet_uuid = {
'uuid': json_response['uuid'], 'uuid': json_response['uuid'],
'wallet_uuid': self.wallet_rial_uuid, 'payee_wallet': self.wallet_rial_uuid,
} }
response = self.client.get(reverse('wallet:application_withdraw_verify_api', kwargs=params), HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_withdraw_verify_api', kwargs=kwargs_payee_wallet_uuid), HTTP_AUTHORIZATION=auth)
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertEqual(response.json()['state'], 5) self.assertEqual(response.json()['state'], 5)
# Desired results # Desired results
response = self.client.get(reverse('wallet:application_account_balance_api', kwargs=kwargs_wallet_uuid), HTTP_AUTHORIZATION=auth) wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex]
self.assertContains(response, 'balance') response = self.client.get(reverse('wallet:application_account_balance_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertEqual(response.json()['balance'], 400) self.assertGreater(response.json()['count'], 1)
from_wallet = response.json()['results'][0]
self.assertEqual(from_wallet['balance'], 400)
params = { params = {
'uuid': self.payer_uuid, 'owner': self.payer_uuid,
'wallet_uuid': self.wallet_rial_uuid,
} }
response = self.client.get(reverse('wallet:application_user_wallet_balance_api', kwargs=params), HTTP_AUTHORIZATION=auth) response = self.client.get(reverse('wallet:application_user_account_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth)
self.assertContains(response, 'balance') self.assertGreater(response.json()['count'], 1)
self.assertEqual(response.json()['balance'], 200) to_wallet = response.json()['results'][0]
self.assertEqual(to_wallet['balance'], 200)
def test_withdraw_flow_wallet_success(self): def test_withdraw_flow_wallet_success(self):
auth = self._create_authorization_header(self.payer_access_token.token) auth = self._create_authorization_header(self.payer_access_token.token)

View file

@ -17,7 +17,7 @@ user_urlpatterns = [
application_urlpatterns = [ application_urlpatterns = [
path('api/application/accounts/', application_views.AccountListAPIView.as_view(), name='application_account_balance_api'), path('api/application/accounts/', application_views.AccountListAPIView.as_view(), name='application_account_balance_api'),
path('api/application/user/<user>/accounts/', application_views.UserAccountListAPIView.as_view(), name='application_user_account_api'), path('api/application/user/<owner>/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/', 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/<uuid>/', application_views.TransactionDetailAPIView.as_view(), name='application_transaction_detail'),
@ -29,11 +29,11 @@ application_urlpatterns = [
path('api/application/<payer_wallet>/deposit/', application_views.DepositSubmitAPIView.as_view(), name='application_deposit_submit_api'), path('api/application/<payer_wallet>/deposit/', application_views.DepositSubmitAPIView.as_view(), name='application_deposit_submit_api'),
path('api/application/<payer_wallet>/deposit/<uuid>/verify', application_views.DepositVerifyAPIView.as_view(), name='application_deposit_verify_api'), path('api/application/<payer_wallet>/deposit/<uuid>/verify', application_views.DepositVerifyAPIView.as_view(), name='application_deposit_verify_api'),
path('api/application/<wallet_uuid>/withdraw/', application_views.WithdrawSubmitAPIView.as_view(), name='application_withdraw_submit_api'), path('api/application/<payee_wallet>/withdraw/', application_views.WithdrawSubmitAPIView.as_view(), name='application_withdraw_submit_api'),
path('api/application/<wallet_uuid>/withdraw/<uuid>/verify', application_views.WithdrawVerifyAPIView.as_view(), name='application_withdraw_verify_api'), path('api/application/<payee_wallet>/withdraw/<uuid>/verify', application_views.WithdrawVerifyAPIView.as_view(), name='application_withdraw_verify_api'),
path('api/application/<wallet_uuid>/', application_views.WalletTransactionListAPIView.as_view(), name='application_transaction_list_api'), path('api/application/<wallet>/', application_views.WalletTransactionListAPIView.as_view(), name='application_transaction_list_api'),
path('api/application/<wallet_uuid>/<uuid>/', application_views.WalletTransactionDetailAPIView.as_view(), name='application_transaction_detail'), path('api/application/<wallet>/<uuid>/', application_views.WalletTransactionDetailAPIView.as_view(), name='application_transaction_detail'),
] ]

View file

@ -71,9 +71,9 @@ class UserAccountListAPIView(generics.ListAPIView):
def get_queryset(self): def get_queryset(self):
qs = super().get_queryset() qs = super().get_queryset()
user_uuid = self.kwargs.get('user') owner_uuid = self.kwargs.get('owner')
user, created = User.objects.get_or_create(uuid=self.kwargs.get('uuid')) user, created = User.objects.get_or_create(uuid=self.kwargs.get('uuid'))
return qs.filter(owner_uuid=user_uuid, owner_type=TypeChoices.USER).all() return qs.filter(owner_uuid=owner_uuid, owner_type=TypeChoices.USER).all()
class TransactionDetailAPIView(generics.RetrieveAPIView): class TransactionDetailAPIView(generics.RetrieveAPIView):
@ -183,10 +183,7 @@ class DepositSubmitAPIView(generics.CreateAPIView):
def get_queryset(self): def get_queryset(self):
payer_wallet_uuid = self.kwargs.get('payer_wallet') payer_wallet_uuid = self.kwargs.get('payer_wallet')
if payer_wallet_uuid:
wallet = get_object_or_404(Wallet.objects.all(), uuid=payer_wallet_uuid) wallet = get_object_or_404(Wallet.objects.all(), uuid=payer_wallet_uuid)
else:
wallet = None
application = get_application(self.request) application = get_application(self.request)
payer_account, created = Account.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,
wallet=wallet) wallet=wallet)
@ -279,11 +276,8 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
required_scopes = ['wallet.application.withdraw:submit'] required_scopes = ['wallet.application.withdraw:submit']
def get_queryset(self): def get_queryset(self):
wallet_uuid = self.kwargs.get('wallet_uuid') payee_wallet_uuid = self.kwargs.get('payee_wallet')
if wallet_uuid: wallet = get_object_or_404(Wallet.objects.all(), uuid=payee_wallet_uuid)
wallet = get_object_or_404(Wallet.objects.all(), uuid=wallet_uuid)
else:
wallet = None
application = get_application(self.request) application = get_application(self.request)
payee_account, created = Account.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,
wallet=wallet) wallet=wallet)
@ -299,12 +293,9 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
payer_wallet_uuid = serializer.validated_data.pop('payer_wallet') payer_wallet_uuid = serializer.validated_data.pop('payer_wallet')
payer_wallet_uuid = payer_wallet_uuid and str(payer_wallet_uuid) payer_wallet_uuid = payer_wallet_uuid and str(payer_wallet_uuid)
payee_wallet_uuid = self.kwargs.get('wallet_uuid') payee_wallet_uuid = self.kwargs.get('payee_wallet')
if payee_wallet_uuid:
payee_wallet = get_object_or_404(Wallet.objects.all(), uuid=payee_wallet_uuid) payee_wallet = get_object_or_404(Wallet.objects.all(), uuid=payee_wallet_uuid)
else:
payee_wallet = None
payer_wallet = get_object_or_404(Wallet.objects.all(), uuid=payer_wallet_uuid) payer_wallet = get_object_or_404(Wallet.objects.all(), uuid=payer_wallet_uuid)
@ -320,26 +311,23 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
wallet=payer_wallet) wallet=payer_wallet)
logger.debug(f"Payer account: {payer_account.uuid}") logger.debug(f"Payer account: {payer_account.uuid}")
uuid = serializer.validated_data.pop('uuid', None) uuid_param = serializer.validated_data.pop('uuid', uuid.uuid4()) # if uuid not provided generate new one to handle get_or_create
details = serializer.validated_data.get('details', {}) details = serializer.validated_data.get('details', {})
reference_id = details.get('reference_id', None) reference_id = details.get('reference_id', None)
logger.debug(f"Transaction UUID: {uuid}, Reference ID: {reference_id}") logger.debug(f"Transaction UUID: {uuid}, Reference ID: {reference_id}")
transaction_params = { transaction_params = {
'uuid': uuid_param,
'application': application, 'application': application,
'payer_account': payer_account, 'payer_account': payer_account,
'payee_account': payee_account, 'payee_account': payee_account,
'amount': serializer.validated_data.get('amount'), 'amount': serializer.validated_data.get('amount'),
} }
if uuid:
transaction_params['uuid'] = uuid
if reference_id: # TODO: checking reference_id
transaction_params['details__reference_id'] = reference_id # if reference_id:
# transaction_params['details__reference_id'] = reference_id
# else:
# logger.error('Missing UUID and Reference ID')
# raise UnprocessableEntity('Missing UUID or reference_id')
instance, created = Transaction.objects.get_or_create(**transaction_params, defaults={ instance, created = Transaction.objects.get_or_create(**transaction_params, defaults={
'details': details 'details': details
}) })
@ -349,7 +337,6 @@ class WithdrawSubmitAPIView(generics.CreateAPIView):
if instance.state == StateChoices.PENDING: if instance.state == StateChoices.PENDING:
return return
# TODO: status code 200 if not created before
if created or instance.state == StateChoices.CREATED: if created or instance.state == StateChoices.CREATED:
instance.submit() instance.submit()
else: else:
@ -365,13 +352,10 @@ class WithdrawVerifyAPIView(generics.RetrieveAPIView):
def get_queryset(self): def get_queryset(self):
application = get_application(self.request) application = get_application(self.request)
wallet_uuid = self.kwargs.get('wallet_uuid') payee_wallet_uuid = self.kwargs.get('payee_wallet')
if wallet_uuid: wallet = get_object_or_404(Wallet.objects.all(), uuid=payee_wallet_uuid)
wallet = get_object_or_404(Wallet.objects.all(), uuid=wallet_uuid)
else:
wallet = None
payee_account = Account.objects.get(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION, wallet=wallet) payee_account = Account.objects.get(owner_uuid=application.uuid, owner_type=TypeChoices.APPLICATION, wallet=wallet)
return Transaction.objects.filter(application=application, payee_wallet=payee_account).all() return Transaction.objects.filter(application=application, payee_account=payee_account).all()
def retrieve(self, request, *args, **kwargs): def retrieve(self, request, *args, **kwargs):
instance = self.get_object() instance = self.get_object()