Skip to content

Commit 49760a3

Browse files
Merge pull request #55 from RandomProgramm3r/develop
feat: Add promo code statistics endpoint This commit introduces a new endpoint for retrieving activation statistics for a specific promo code. - `GET /api/business/promo/{id}/stat`: Allows a company to view detailed statistics for their promo code, including the total number of activations and a breakdown of activations by country. Key changes include: - A `CompanyPromoStatAPIView` that handles the logic for retrieving and serializing the statistics. - New `CountryStatSerializer` and `PromoStatSerializer` to structure the response data. - A new URL pattern in `business/urls.py` to route to the new view. - A fix in `BaseUserTestCase` to clear `OutstandingToken` after tests.
2 parents da26418 + d1c19c5 commit 49760a3

File tree

4 files changed

+80
-0
lines changed

4 files changed

+80
-0
lines changed

promo_code/business/serializers.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -538,3 +538,17 @@ def validate(self, data):
538538
instance=self.instance,
539539
)
540540
return validator.validate()
541+
542+
543+
class CountryStatSerializer(rest_framework.serializers.Serializer):
544+
"""Serializer for activation statistics by country."""
545+
546+
country = rest_framework.serializers.CharField()
547+
activations_count = rest_framework.serializers.IntegerField()
548+
549+
550+
class PromoStatSerializer(rest_framework.serializers.Serializer):
551+
"""Serializer for overall promo code statistics."""
552+
553+
activations_count = rest_framework.serializers.IntegerField()
554+
countries = CountryStatSerializer(many=True)

promo_code/business/urls.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,9 @@
3131
business.views.CompanyPromoDetailView.as_view(),
3232
name='promo-detail',
3333
),
34+
django.urls.path(
35+
'promo/<uuid:id>/stat',
36+
business.views.CompanyPromoStatAPIView.as_view(),
37+
name='promo-statistics',
38+
),
3439
]

promo_code/business/views.py

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import re
22

33
import django.db.models
4+
import django.shortcuts
45
import rest_framework.generics
56
import rest_framework.permissions
67
import rest_framework.response
78
import rest_framework.status
9+
import rest_framework.views
810
import rest_framework_simplejwt.views
911

1012
import business.models
@@ -13,6 +15,7 @@
1315
import business.serializers
1416
import business.utils.auth
1517
import business.utils.tokens
18+
import user.models
1619

1720

1821
class CompanySignUpView(rest_framework.generics.CreateAPIView):
@@ -153,3 +156,60 @@ class CompanyPromoDetailView(rest_framework.generics.RetrieveUpdateAPIView):
153156
# Use an enriched base queryset without pre-filtering by company,
154157
# so that ownership mismatches raise 403 Forbidden (not 404 Not Found).
155158
queryset = business.models.Promo.objects.with_related()
159+
160+
161+
class CompanyPromoStatAPIView(rest_framework.views.APIView):
162+
"""
163+
API endpoint for retrieving promo code statistics.
164+
"""
165+
166+
permission_classes = [
167+
rest_framework.permissions.IsAuthenticated,
168+
business.permissions.IsPromoOwner,
169+
]
170+
171+
def get(self, request, id, *args, **kwargs):
172+
promo = django.shortcuts.get_object_or_404(
173+
business.models.Promo,
174+
id=id,
175+
)
176+
177+
self.check_object_permissions(self.request, promo)
178+
179+
total_activations = promo.activations_history.count()
180+
181+
countries_stats = (
182+
user.models.PromoActivationHistory.objects.filter(promo=promo)
183+
.values(
184+
'user__other__country',
185+
)
186+
.annotate(
187+
activations_count=django.db.models.Count('id'),
188+
)
189+
.order_by(
190+
'user__other__country',
191+
)
192+
)
193+
194+
countries_data = [
195+
{
196+
'country': item['user__other__country'],
197+
'activations_count': item['activations_count'],
198+
}
199+
for item in countries_stats
200+
]
201+
202+
response_data = {
203+
'activations_count': total_activations,
204+
'countries': countries_data,
205+
}
206+
207+
serializer = business.serializers.PromoStatSerializer(
208+
data=response_data,
209+
)
210+
serializer.is_valid(raise_exception=True)
211+
212+
return rest_framework.response.Response(
213+
serializer.validated_data,
214+
status=rest_framework.status.HTTP_200_OK,
215+
)

promo_code/user/tests/user/base.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ def tearDown(self):
8484
user.models.PromoLike.objects.all().delete()
8585
user.models.User.objects.all().delete()
8686
tb_models.BlacklistedToken.objects.all().delete()
87+
tb_models.OutstandingToken.objects.all().delete()
8788
django_redis.get_redis_connection('default').flushall()
8889
super().tearDown()
8990

0 commit comments

Comments
 (0)