diff --git a/apps/promotions/models.py b/apps/promotions/models.py index b04bf23..4825dc2 100644 --- a/apps/promotions/models.py +++ b/apps/promotions/models.py @@ -71,7 +71,7 @@ class Event(BaseModel): def analyze(self): for plan in Plan.objects.related_to_event(self): - plan.process_event(event=self) + yield plan.process_event(event=self) class PlanQuerySet(models.QuerySet): diff --git a/apps/promotions/tasks.py b/apps/promotions/tasks.py index 943be9e..a75a2b4 100644 --- a/apps/promotions/tasks.py +++ b/apps/promotions/tasks.py @@ -5,4 +5,6 @@ from main import celery_app @celery_app.task def analyze_event_task(event_uuid): event = Event.objects.get(uuid=event_uuid) - event.analyze() + for plan_analyze_result in event.analyze(): + for promotion in plan_analyze_result: + print(promotion) diff --git a/apps/promotions/tests.py b/apps/promotions/tests.py index 5a04449..137eea3 100644 --- a/apps/promotions/tests.py +++ b/apps/promotions/tests.py @@ -7,6 +7,7 @@ from django.utils import timezone from oauth2_provider.models import get_access_token_model, get_application_model from rest_framework.test import APITestCase, override_settings, APIClient +from apps.promotions.tasks import analyze_event_task from apps.users.models import User from apps.promotions.models import Plan, Promotion, EventSaver, ProcessorTypeChoices, Event, Recipient @@ -64,7 +65,8 @@ class ApplicationApiFlowsTests(APITestCase): application_uuid = uuid.UUID(application_uuid_hex) application_access_token = '14naVsdKCbKNOhnElPyXcrwSnqqFbm' user_access_token = '24naVsdKCbKNOhnElPyXcrwSnqqFbm' - user_uuid = uuid.UUID('b14e8b86-8f4a-44d9-b29d-badceb470051') + user_1_uuid = uuid.UUID('b14e8b86-8f4a-44d9-b29d-badceb470051') + user_2_uuid = uuid.UUID('b14e8b86-8f4a-44d9-b29d-badceb470052') first_ad_view_reward_label = 'first_ad_view_reward_label' referral_reward_label = 'referral_reward_label' settlement_reward_label = 'settlement_reward_label' @@ -92,7 +94,8 @@ class ApplicationApiFlowsTests(APITestCase): # self.submit_withdraw_success_patcher.start() # self.verify_withdraw_success_patcher.start() - self.user, _ = User.objects.get_or_create(pk=self.user_uuid) + self.user_1, _ = User.objects.get_or_create(pk=self.user_1_uuid) + self.user_2, _ = User.objects.get_or_create(pk=self.user_2_uuid) expire_datetime = timezone.now() + timedelta(seconds=3600) @@ -101,7 +104,6 @@ class ApplicationApiFlowsTests(APITestCase): self.application_access_token, _created = AccessToken.objects.update_or_create( token=self.application_access_token, defaults={ - "user": self.user, "client_id": self.client_id, # "client_owner": owner, "application_id": self.application_uuid, @@ -113,7 +115,7 @@ class ApplicationApiFlowsTests(APITestCase): self.user_access_token, _created = AccessToken.objects.update_or_create( token=self.user_access_token, defaults={ - "user": self.user, + "user": self.user_1, "client_id": self.client_id, # "client_owner": owner, "application_id": self.application_uuid, @@ -127,44 +129,6 @@ class ApplicationApiFlowsTests(APITestCase): uuid=self.application_uuid, ) - self.first_ad_view_reward_event_saver, _created = EventSaver.objects.get_or_create( - title=self.first_ad_view_reward_label, - event_label=self.first_ad_view_reward_label, - save_once=True, - ) - - self.first_ad_view_reward_plan, _created = Plan.objects.get_or_create( - title = self.first_ad_view_reward_label, - balance=10000, - user = self.user, - application = self.application, - event_list=[self.first_ad_view_reward_label] - ) - - self.first_ad_view_reward_recipient, _created = Recipient.objects.get_or_create( - label = self.first_ad_view_reward_label, - plan = self.first_ad_view_reward_plan, - wallet_uuid = self.user_uuid, - recipient_uuid_field="event:user", - base_amount_field="event:base_amount", - - ) - - self.referral_reward_saver, _created = EventSaver.objects.get_or_create( - title=self.referral_reward_label, - event_label=self.referral_reward_label, - save_once=True, - ) - - self.referral_reward_plan, _created = Plan.objects.get_or_create( - title = self.referral_reward_label, - balance=10000, - user = self.user, - application = self.application, - event_list=[self.referral_reward_label] - ) - - def tearDown(self): super().tearDown() @@ -172,11 +136,34 @@ class ApplicationApiFlowsTests(APITestCase): return "Bearer {0}".format(token) def test_first_ad_view_reward_success(self): + self.first_ad_view_reward_event_saver, _created = EventSaver.objects.get_or_create( + title=self.first_ad_view_reward_label, + event_label=self.first_ad_view_reward_label, + save_once=True, + ) + + self.first_ad_view_reward_plan, _created = Plan.objects.get_or_create( + title=self.first_ad_view_reward_label, + balance=10000, + user=self.user_1, + application=self.application, + event_list=[self.first_ad_view_reward_label] + ) + + self.first_ad_view_reward_recipient, _created = Recipient.objects.get_or_create( + label=self.first_ad_view_reward_label, + plan=self.first_ad_view_reward_plan, + wallet_uuid=self.user_1_uuid, + recipient_uuid_field="event:user", + base_amount_field="event:base_amount", + + ) + auth = self._create_authorization_header(self.user_access_token.token) event_create_data = { 'label': self.first_ad_view_reward_label, "data": { - 'user': self.user_uuid, + 'user': self.user_1_uuid, 'base_amount':800 } } @@ -186,328 +173,91 @@ class ApplicationApiFlowsTests(APITestCase): self.first_ad_view_reward_plan.refresh_from_db() self.assertEqual(self.first_ad_view_reward_plan.balance, 10000 - 800) - response = self.client.post(reverse('promotions:promote', kwargs={"plan": self.first_ad_view_reward_plan.uuid}), event_create_data, HTTP_AUTHORIZATION=auth, format='json') - print(response.json()) + # response = self.client.post(reverse('promotions:promote', kwargs={"plan": self.first_ad_view_reward_plan.uuid}), event_create_data, HTTP_AUTHORIZATION=auth, format='json') + # print(response.json()) - return def test_referral_reward_success(self): + self.referral_reward_event_saver, _created = EventSaver.objects.get_or_create( + title=self.referral_reward_label, + event_label=self.referral_reward_label, + save_once=True, + ) + + self.referral_reward_plan, _created = Plan.objects.get_or_create( + title=self.referral_reward_label, + balance=10000, + user=self.user_1, + application=self.application, + event_list=[self.referral_reward_label] + ) + + self.referral_reward_recipient, _created = Recipient.objects.get_or_create( + label=self.referral_reward_label, + plan=self.referral_reward_plan, + wallet_uuid=self.user_1_uuid, + recipient_uuid_field="event:referral", + base_amount_field="1000", + + ) + auth = self._create_authorization_header(self.user_access_token.token) event_create_data = { - 'label': self.first_ad_view_reward_label, + 'label': self.referral_reward_label, "data": { - 'user': self.user_uuid, - 'referral': self.user_uuid + 'user': self.user_1_uuid, + 'referral': self.user_2_uuid } } - response = self.client.post(reverse('promotions:application-events-list'), event_create_data, HTTP_AUTHORIZATION=auth, format='json') - event = Event.objects.get(user=self.user, label=self.first_ad_view_reward_label) - event.analyze() - print(event) - return - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 300) - params = { - 'owner': self.payee_uuid, + response = self.client.post(reverse('promotions:promote', kwargs={"plan": self.referral_reward_plan.uuid}), event_create_data, HTTP_AUTHORIZATION=auth, format='json') + print(response.json()) + self.referral_reward_plan.refresh_from_db() + self.assertEqual(self.referral_reward_plan.balance, 10000 - 1000) + self.assertEqual(response.json()['promotions'][0]['user'], str(self.user_2_uuid)) + + + def test_referral_reward_submit_event_success(self): + self.referral_reward_event_saver, _created = EventSaver.objects.get_or_create( + title=self.referral_reward_label, + event_label=self.referral_reward_label, + save_once=True, + ) + + self.referral_reward_plan, _created = Plan.objects.get_or_create( + title=self.referral_reward_label, + balance=10000, + user=self.user_1, + application=self.application, + event_list=[self.referral_reward_label] + ) + + self.referral_reward_recipient, _created = Recipient.objects.get_or_create( + label=self.referral_reward_label, + plan=self.referral_reward_plan, + wallet_uuid=self.user_1_uuid, + recipient_uuid_field="event:referral", + base_amount_field="1000", + + ) + + auth = self._create_authorization_header(self.user_access_token.token) + event_create_data = { + 'label': self.referral_reward_label, + "data": { + 'user': self.user_1_uuid, + 'referral': self.user_2_uuid + } } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 0) - - # Deposit process - data = { - 'amount': 100, - 'payee': self.payee_uuid, - 'payee_type': TypeChoices.USER, - 'payee_wallet': self.wallet_rial_uuid, - } - kwargs_payer_wallet = { - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 201) - json_response = response.json() - - kwargs_verify = { - 'uuid': json_response['uuid'], - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.get(reverse('wallet:application_deposit_verify_api', kwargs=kwargs_verify), HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 200) - self.assertEqual(response.json()['state'], 5) - - # Desired results - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 200) - - params = { - 'owner': self.payee_uuid, - } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 100) - - def test_deposit_flow_insufficient_balance(self): - auth = self._create_authorization_header(self.application_access_token.token) - - # Checking wallets initials values(application balance = 300 and payee balance = zero) - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 300) - params = { - 'owner': self.payee_uuid, - } - - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 0) - - # Deposit process - data = { - 'amount': 500, - 'payee': self.payee_uuid, - 'payee_type': TypeChoices.USER, - 'payee_wallet': self.wallet_rial_uuid, - } - kwargs_payer_wallet = { - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), - data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 422) - - @override_settings(ALLOWED_NEGATIVE_BALANCE_APPLICATIONS=[application_uuid_hex]) - def test_deposit_flow_skip_insufficient_balance_for_allowed_negative_balance_applications(self): - auth = self._create_authorization_header(self.application_access_token.token) - - # Checking wallets initials values(application balance = 300 and payee balance = zero) - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 300) - params = { - 'owner': self.payee_uuid, - } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 0) - - # Deposit process - data = { - 'amount': 500, - 'payee': self.payee_uuid, - 'payee_type': TypeChoices.USER, - 'payee_wallet': self.wallet_rial_uuid, - } - kwargs_payer_wallet = { - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), - data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 201) - - def test_deposit_flow_zero_amount(self): - # TODO: wallet - auth = self._create_authorization_header(self.application_access_token.token) - - # Deposit process - data = { - 'amount': 0, - 'payee': self.payee_uuid, - 'payee_type': TypeChoices.USER, - 'payee_wallet': self.wallet_rial_uuid, - } - kwargs_payer_wallet = { - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 400) - - def test_deposit_flow_negative_amount(self): - # TODO: wallet - auth = self._create_authorization_header(self.application_access_token.token) - - # Deposit process - data = { - 'amount': -100, - 'payee': self.payee_uuid, - 'payee_type': TypeChoices.USER, - 'payee_wallet': self.wallet_rial_uuid, - } - kwargs_payer_wallet = { - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 400) - - def test_deposit_flow_prevent_double_spending(self): - auth = self._create_authorization_header(self.application_access_token.token) - - # Checking wallets initials values(application balance = 300 and payee balance = zero) - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 300) - params = { - 'owner': self.payee_uuid, - } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 0) - - # Deposit process - data = { - 'amount': 200, - 'payee': self.payee_uuid, - 'payee_type': TypeChoices.USER, - 'payee_wallet': self.wallet_rial_uuid, - } - kwargs_payer_wallet = { - 'payer_wallet': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 201) - - response = self.client.post(reverse('wallet:application_deposit_submit_api', kwargs=kwargs_payer_wallet), data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 422) - - def test_withdraw_flow_success(self): - auth = self._create_authorization_header(self.payer_access_token.token) - - # Checking wallets initials values(application balance = 300 and payee balance = zero) - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 300) - params = { - 'owner': self.payer_uuid, - } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 300) - - # Deposit process - data = { - 'amount': 100, - 'payer': self.payer_uuid, - 'payer_type': TypeChoices.USER, - 'payer_wallet': self.wallet_rial_uuid, - } - - kwargs_payee_wallet = { - 'payee_wallet': self.wallet_rial_uuid, - } - - 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) - json_response = response.json() - - kwargs_payee_wallet_uuid = { - 'uuid': json_response['uuid'], - 'payee_wallet': self.wallet_rial_uuid, - } - 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.json()['state'], 5) - - # Desired results - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 400) - params = { - 'owner': self.payer_uuid, - } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 200) - - def test_withdraw_flow_zero_amount(self): - auth = self._create_authorization_header(self.payer_access_token.token) - - kwargs_payee_wallet = { - 'payee_wallet': self.wallet_rial_uuid, - } - - # Deposit process - data = { - 'amount': 0, - 'payer': self.payer_uuid, - 'payer_type': TypeChoices.USER, - 'payer_account': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_withdraw_submit_api', kwargs=kwargs_payee_wallet), - data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 400) - - def test_withdraw_flow_negative_amount(self): - auth = self._create_authorization_header(self.payer_access_token.token) - kwargs_payee_wallet = { - 'payee_wallet': self.wallet_rial_uuid, - } - # Deposit process - data = { - 'amount': -500, - 'payer': self.payer_uuid, - 'payer_type': TypeChoices.USER, - 'payer_account': self.wallet_rial_uuid, - } - response = self.client.post(reverse('wallet:application_withdraw_submit_api', kwargs=kwargs_payee_wallet), data=data, HTTP_AUTHORIZATION=auth) - self.assertEqual(response.status_code, 400) - - def test_withdraw_flow_prevent_double_spending(self): - auth = self._create_authorization_header(self.payer_access_token.token) - - kwargs_wallet_uuid = { - 'wallet_uuid': self.wallet_rial_uuid, - } - # Checking wallets initials values(application balance = 300 and payee balance = zero) - wallets = [self.wallet_rial_uuid.hex, self.wallet_reward_uuid.hex] - response = self.client.get(reverse('wallet:application_account_list_api'), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - from_wallet = response.json()['results'][0] - self.assertEqual(from_wallet['balance'], 300) - params = { - 'owner': self.payer_uuid, - } - response = self.client.get(reverse('wallet:application_user_account_list_api', kwargs=params), query_params={'wallet': ','.join(wallets)}, HTTP_AUTHORIZATION=auth) - self.assertGreater(response.json()['count'], 1) - to_wallet = response.json()['results'][0] - self.assertEqual(to_wallet['balance'], 300) - - # Deposit process - data = { - 'amount': 100, - 'payer': self.payer_uuid, - 'payer_type': TypeChoices.USER, - 'payer_wallet': self.wallet_rial_uuid, - } - - kwargs_payee_wallet = { - 'payee_wallet': self.wallet_rial_uuid, - } - - 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) - - 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(Event.objects.count(), 0) + response = self.client.post(reverse('promotions:event'), event_create_data, HTTP_AUTHORIZATION=auth, format='json') + print(response.json()) + self.referral_reward_plan.refresh_from_db() + self.assertEqual(self.referral_reward_plan.balance, 10000) + self.assertEqual(Event.objects.count(), 1) + event = Event.objects.first() + analyze_event_task(event.uuid) + self.referral_reward_plan.refresh_from_db() + self.assertEqual(self.referral_reward_plan.balance, 10000 - 1000) + diff --git a/apps/promotions/urls.py b/apps/promotions/urls.py index 4d2214b..8f07091 100644 --- a/apps/promotions/urls.py +++ b/apps/promotions/urls.py @@ -5,7 +5,7 @@ from utils.router import ProfileRouter from . import views from django.urls import NoReverseMatch, path, re_path, include -from .views import ApplicationPromoteUserApiView +from .views import ApplicationPromoteUserApiView, ApplicationSubmitEventAPIView app_name = 'promotions' @@ -19,4 +19,5 @@ router.register(r'plans', views.UserViewSet, basename='user') urlpatterns = [ path('api/v1/', include(router.urls), name='events'), path('api/v1/promote//', ApplicationPromoteUserApiView.as_view(), name='promote'), + path('api/v1/event/', ApplicationSubmitEventAPIView.as_view(), name='event'), ] diff --git a/apps/promotions/views.py b/apps/promotions/views.py index 396f3a0..5504efc 100644 --- a/apps/promotions/views.py +++ b/apps/promotions/views.py @@ -180,3 +180,20 @@ class ApplicationPromoteUserApiView(CreateAPIView): +class ApplicationSubmitEventAPIView(CreateAPIView): + model = Promotion + serializer_class = PromoteSerializer + + def create(self, request, *args, **kwargs): + serializer = self.get_serializer(data=request.data) + serializer.is_valid(raise_exception=True) + data = serializer.validated_data + application = get_application(self.request) + event_saver: EventSaver = EventSaver.objects.filter(event_label=serializer.validated_data['label']).first() + event = event_saver.save_event(user=None, application=application, **serializer.validated_data) + + analyze_event_task.delay(event.uuid) + + headers = self.get_success_headers(serializer.data) + return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) +