get plan details

This commit is contained in:
Sayyid Hamid Mahdavi 2026-02-22 13:59:48 +03:30
parent 81e3e7776d
commit 61f3c8a920
6 changed files with 94 additions and 37 deletions

View file

@ -0,0 +1,29 @@
# Generated by Django 6.0.2 on 2026-02-22 10:12
import django_minio_backend.models
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('promotions', '0006_event_promotions_event_data_bc656abc_and_more'),
]
operations = [
migrations.AlterModelOptions(
name='event',
options={'ordering': ('-created_at',)},
),
migrations.AddField(
model_name='plan',
name='banner',
field=models.ImageField(blank=True, null=True, storage=django_minio_backend.models.MinioBackend(), upload_to=django_minio_backend.models.iso_date_prefix),
),
migrations.AddField(
model_name='plan',
name='description_details',
field=models.JSONField(blank=True, default={}, verbose_name='description details'),
preserve_default=False,
),
]

View file

@ -5,6 +5,7 @@ from django.contrib.postgres.indexes import GinIndex
from django.db import models, transaction from django.db import models, transaction
from django.db.models import F from django.db.models import F
from django.utils import timezone from django.utils import timezone
from django_minio_backend import MinioBackend, iso_date_prefix
from oauth2_provider.settings import oauth2_settings from oauth2_provider.settings import oauth2_settings
@ -105,7 +106,9 @@ class Plan(BaseModel):
null=True, blank=True) null=True, blank=True)
event_list = models.JSONField(default=list) event_list = models.JSONField(default=list)
title = models.CharField(max_length=255, verbose_name=_('title'), db_index=True) title = models.CharField(max_length=255, verbose_name=_('title'), db_index=True)
banner = models.ImageField(null=True, blank=True, storage=MinioBackend(), upload_to=iso_date_prefix)
description = models.TextField(verbose_name=_('description'), blank=True) description = models.TextField(verbose_name=_('description'), blank=True)
description_details = models.JSONField(verbose_name=_('description details'), blank=True)
processor = models.CharField(max_length=64, verbose_name=_('processor'), db_index=True, processor = models.CharField(max_length=64, verbose_name=_('processor'), db_index=True,
choices=ProcessorTypeChoices.choices) # TODO: processor type choices=ProcessorTypeChoices.choices) # TODO: processor type
data = models.JSONField(default=dict, verbose_name=_('data'), null=True, blank=True) data = models.JSONField(default=dict, verbose_name=_('data'), null=True, blank=True)

View file

@ -1,6 +1,6 @@
from rest_framework import serializers from rest_framework import serializers
from .models import Promotion, Plan, Event from .models import Promotion, Plan, Event, Recipient
class PromotionSerializer(serializers.ModelSerializer): class PromotionSerializer(serializers.ModelSerializer):
@ -74,3 +74,27 @@ class PromoteSerializer(serializers.ModelSerializer):
"label", "label",
"data", "data",
) )
class UserRecipientSerializer(serializers.ModelSerializer):
class Meta:
model = Recipient
fields = ['label',
"base_amount_field"]
class UserPlanSerializer(serializers.ModelSerializer):
recipients = UserRecipientSerializer(many=True, read_only=True)
class Meta:
model = Plan
fields = ("title",
'banner',
"description",
"description_details",
"recipients",
)
read_only_fields = ("title", "description", "description_details", 'banner', "recipients")
# def get_promotion_amount(self, obj):
# user = self.context['request'].user
# return obj.calculate_promotion(user)

View file

@ -12,7 +12,7 @@ app_name = 'promotions'
router = DefaultRouter() router = DefaultRouter()
# router.register(r'application', views.ApplicationPromotionViewSet, basename='application_promotions') # router.register(r'application', views.ApplicationPromotionViewSet, basename='application_promotions')
# router.register(r'events', views.ApplicationViewSet, basename='application-events') # router.register(r'events', views.ApplicationViewSet, basename='application-events')
# router.register(r'plans', views.UserViewSet, basename='user') router.register(r'plans', views.UserPlanViewSet, basename='user-plans')
# urlpatterns = # urlpatterns =
@ -20,7 +20,6 @@ urlpatterns = [
path('api/v1/plans/<plan>/', ApplicationPromoteUserApiView.as_view(), name='promotion-create'), path('api/v1/plans/<plan>/', ApplicationPromoteUserApiView.as_view(), name='promotion-create'),
path('api/v1/plans/<plan>/promotins', ApplicationPromotionListApiView.as_view(), name='promotion-list'), path('api/v1/plans/<plan>/promotins', ApplicationPromotionListApiView.as_view(), name='promotion-list'),
path('api/v1/events/submit', ApplicationEventSubmitAPIView.as_view(), name='event-create'), path('api/v1/events/submit', ApplicationEventSubmitAPIView.as_view(), name='event-create'),
path('api/v1/events/get', ApplicationEventRetrieveAPIView.as_view(), name='event-retrieve'), # path('api/v1/events/get', ApplicationEventRetrieveAPIView.as_view(), name='event-retrieve'),
path('api/v1/', include(router.urls), name='events'), path('api/v2/', include(router.urls)),
] ]

View file

@ -10,7 +10,7 @@ from apps.gooyal_oauth2.rest_framework import IsAuthenticatedOrTokenMatchesOASRe
from apps.gooyal_oauth2.utils import get_application from apps.gooyal_oauth2.utils import get_application
from utils.exceptions import UnprocessableEntity from utils.exceptions import UnprocessableEntity
from .models import Plan, Promotion, EventSaver from .models import Plan, Promotion, EventSaver
from .serializers import PlanSerializer, PromotionSerializer, EventSerializer, PromoteSerializer from .serializers import PlanSerializer, PromotionSerializer, EventSerializer, PromoteSerializer, UserPlanSerializer
from .tasks import analyze_event_task from .tasks import analyze_event_task
from ..users.models import User from ..users.models import User
@ -100,14 +100,15 @@ class ApplicationViewSet(
serializer.instance = event serializer.instance = event
class UserViewSet(mixins.RetrieveModelMixin, class UserPlanViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin, # mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericViewSet): GenericViewSet):
serializer_class = PlanSerializer serializer_class = UserPlanSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements] permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = { required_alternate_scopes = {
"GET": [["promotions.user.self-plans:list-retrieve"]], "GET": [["promotions.user.plans:list-retrieve"]],
"POST": [["promotions.user.self-plans:list-retrieve"]], "POST": [["promotions.user.plans:list-retrieve"]],
} }
def get_queryset(self): def get_queryset(self):
@ -117,39 +118,39 @@ class UserViewSet(mixins.RetrieveModelMixin,
queryset = Plan.objects.all() queryset = Plan.objects.all()
return queryset return queryset
@extend_schema(responses=PlanSerializer(many=True)) # @extend_schema(responses=PlanSerializer(many=True))
@action(detail=False, methods=['POST'], serializer_class=PlanSerializer) # @action(detail=False, methods=['POST'], serializer_class=PlanSerializer)
def available(self, request): # def available(self, request):
serializer = self.get_serializer(data=self.request.data) # serializer = self.get_serializer(data=self.request.data)
serializer.is_valid(raise_exception=True) # serializer.is_valid(raise_exception=True)
print(serializer.validated_data) # print(serializer.validated_data)
plans = self.paginate_queryset(self.filter_queryset(self.get_queryset())) # plans = self.paginate_queryset(self.filter_queryset(self.get_queryset()))
for plan in plans: # for plan in plans:
plan.calculate_promotion(**serializer.validated_data) # plan.calculate_promotion(**serializer.validated_data)
serializer = self.get_serializer(plans, many=True) # serializer = self.get_serializer(plans, many=True)
return self.get_paginated_response(serializer.data) # return self.get_paginated_response(serializer.data)
@action(detail=True, methods=['POST'], serializer_class=EventSerializer) @action(detail=True, methods=['POST'], serializer_class=PromoteSerializer)
def promote(self, request, pk=None): def promote(self, request, pk=None):
serializer = self.get_serializer(data=self.request.data) plan = self.get_object()
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True) serializer.is_valid(raise_exception=True)
data = serializer.validated_data
if hasattr(self.request, 'user'):
user = self.request.user
else:
user = None
application = get_application(self.request) application = get_application(self.request)
# EventSaver.objects.first(event_label=serializer.validated_data['event_label'], valid_application__contains=application.uuid)
event_saver: EventSaver = EventSaver.objects.filter(event_label=serializer.validated_data['label']).first() event_saver: EventSaver = EventSaver.objects.filter(event_label=serializer.validated_data['label']).first()
try:
event = event_saver.save_event(user=user, application=application, **serializer.validated_data)
except Exception as e:
raise exceptions.ValidationError(str(e))
plan: Plan = self.get_object() user = self.request.user.pk or serializer.validated_data['user']
# try:
event = event_saver.save_event(user=user, application=application, **serializer.validated_data)
# except Exception as e:
# raise exceptions.ValidationError(str(e))
return result_list = plan.process_event(event)
data["promotions"] = result_list
headers = self.get_success_headers(serializer.data)
return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)
class ApplicationPromoteUserApiView(CreateAPIView): class ApplicationPromoteUserApiView(CreateAPIView):

View file

@ -36,6 +36,7 @@ INSTALLED_APPS = [
'django.contrib.sessions', 'django.contrib.sessions',
'django.contrib.messages', 'django.contrib.messages',
'django.contrib.staticfiles', 'django.contrib.staticfiles',
'django.contrib.postgres',
# pip installed apps # pip installed apps
'drf_spectacular', 'drf_spectacular',