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.models import F
from django.utils import timezone
from django_minio_backend import MinioBackend, iso_date_prefix
from oauth2_provider.settings import oauth2_settings
@ -105,7 +106,9 @@ class Plan(BaseModel):
null=True, blank=True)
event_list = models.JSONField(default=list)
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_details = models.JSONField(verbose_name=_('description details'), blank=True)
processor = models.CharField(max_length=64, verbose_name=_('processor'), db_index=True,
choices=ProcessorTypeChoices.choices) # TODO: processor type
data = models.JSONField(default=dict, verbose_name=_('data'), null=True, blank=True)

View file

@ -1,6 +1,6 @@
from rest_framework import serializers
from .models import Promotion, Plan, Event
from .models import Promotion, Plan, Event, Recipient
class PromotionSerializer(serializers.ModelSerializer):
@ -74,3 +74,27 @@ class PromoteSerializer(serializers.ModelSerializer):
"label",
"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.register(r'application', views.ApplicationPromotionViewSet, basename='application_promotions')
# 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 =
@ -20,7 +20,6 @@ urlpatterns = [
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/events/submit', ApplicationEventSubmitAPIView.as_view(), name='event-create'),
path('api/v1/events/get', ApplicationEventRetrieveAPIView.as_view(), name='event-retrieve'),
path('api/v1/', include(router.urls), name='events'),
# path('api/v1/events/get', ApplicationEventRetrieveAPIView.as_view(), name='event-retrieve'),
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 utils.exceptions import UnprocessableEntity
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 ..users.models import User
@ -100,14 +100,15 @@ class ApplicationViewSet(
serializer.instance = event
class UserViewSet(mixins.RetrieveModelMixin,
mixins.ListModelMixin,
class UserPlanViewSet(mixins.RetrieveModelMixin,
# mixins.ListModelMixin,
mixins.CreateModelMixin,
GenericViewSet):
serializer_class = PlanSerializer
serializer_class = UserPlanSerializer
permission_classes = [IsAuthenticatedOrTokenMatchesOASRequirements]
required_alternate_scopes = {
"GET": [["promotions.user.self-plans:list-retrieve"]],
"POST": [["promotions.user.self-plans:list-retrieve"]],
"GET": [["promotions.user.plans:list-retrieve"]],
"POST": [["promotions.user.plans:list-retrieve"]],
}
def get_queryset(self):
@ -117,39 +118,39 @@ class UserViewSet(mixins.RetrieveModelMixin,
queryset = Plan.objects.all()
return queryset
@extend_schema(responses=PlanSerializer(many=True))
@action(detail=False, methods=['POST'], serializer_class=PlanSerializer)
def available(self, request):
serializer = self.get_serializer(data=self.request.data)
serializer.is_valid(raise_exception=True)
print(serializer.validated_data)
plans = self.paginate_queryset(self.filter_queryset(self.get_queryset()))
for plan in plans:
plan.calculate_promotion(**serializer.validated_data)
serializer = self.get_serializer(plans, many=True)
return self.get_paginated_response(serializer.data)
# @extend_schema(responses=PlanSerializer(many=True))
# @action(detail=False, methods=['POST'], serializer_class=PlanSerializer)
# def available(self, request):
# serializer = self.get_serializer(data=self.request.data)
# serializer.is_valid(raise_exception=True)
# print(serializer.validated_data)
# plans = self.paginate_queryset(self.filter_queryset(self.get_queryset()))
# for plan in plans:
# plan.calculate_promotion(**serializer.validated_data)
# serializer = self.get_serializer(plans, many=True)
# 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):
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)
if hasattr(self.request, 'user'):
user = self.request.user
else:
user = None
data = serializer.validated_data
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()
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):

View file

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