feat: add community contribution ranks

This commit is contained in:
2026-09-29 22:18:57 +03:30
parent 0f6220f72c
commit 77567178ad
46 changed files with 2206 additions and 23 deletions

View File

@@ -1,3 +1,5 @@
from typing import Literal, Optional
from ninja import Schema
from datetime import datetime
@@ -64,6 +66,30 @@ class PaymentDetailOut(Schema):
verified_at: str | None = None
event: dict
class UserPaymentEventSchema(Schema):
title: str
slug: str
image_url: Optional[str] = None
class UserPaymentSchema(Schema):
event: UserPaymentEventSchema
base_amount: int
discount_amount: int
amount: int
status: Literal["initiated", "pending", "paid", "failed", "canceled"]
created_at: datetime
paid_at: Optional[datetime] = None
class PaginatedUserPaymentsSchema(Schema):
count: int
page: int
page_size: int
total_pages: int
results: list[UserPaymentSchema]
class CouponVerifyIn(Schema):
event_id: int
code: str

View File

@@ -2,6 +2,7 @@ from django.conf import settings
from django.shortcuts import redirect, get_object_or_404
from django.utils import timezone
from django.db.models import Count, Q
from typing import List
from ninja import Query, Router
from ninja.errors import HttpError
@@ -22,11 +23,70 @@ from apps.payments.api.schemas import (
DiscountCodeWriteSchema,
PagedDiscountCodeSchema,
PaymentDetailOut,
PaginatedUserPaymentsSchema,
UserPaymentSchema,
)
payments_router = Router(tags=["Payments"])
@payments_router.get("/me", response=List[UserPaymentSchema], auth=jwt_auth)
def my_payments(request):
status_names = {
Payment.OrderStatusChoices.INIT: "initiated",
Payment.OrderStatusChoices.PENDING: "pending",
Payment.OrderStatusChoices.PAID: "paid",
Payment.OrderStatusChoices.FAILED: "failed",
Payment.OrderStatusChoices.CANCELED: "canceled",
}
payments = Payment.objects.filter(user=request.auth).select_related("event").order_by("-created_at")[:50]
return [
_user_payment_payload(request, payment, status_names)
for payment in payments
]
def _user_payment_payload(request, payment, status_names):
return {
"event": {
"title": payment.event.title,
"slug": payment.event.slug,
"image_url": request.build_absolute_uri(payment.event.featured_image.url)
if payment.event.featured_image
else None,
},
"base_amount": payment.base_amount,
"discount_amount": payment.discount_amount,
"amount": payment.amount,
"status": status_names[payment.status],
"created_at": payment.created_at,
"paid_at": payment.verified_at,
}
@payments_router.get("/me/paginated", response=PaginatedUserPaymentsSchema, auth=jwt_auth)
def my_payments_paginated(request, page: int = Query(1, ge=1)):
page_size = 10
status_names = {
Payment.OrderStatusChoices.INIT: "initiated",
Payment.OrderStatusChoices.PENDING: "pending",
Payment.OrderStatusChoices.PAID: "paid",
Payment.OrderStatusChoices.FAILED: "failed",
Payment.OrderStatusChoices.CANCELED: "canceled",
}
queryset = Payment.objects.filter(user=request.auth).select_related("event").order_by("-created_at", "-id")
count = queryset.count()
total_pages = max(1, (count + page_size - 1) // page_size)
start = (page - 1) * page_size
return {
"count": count,
"page": page,
"page_size": page_size,
"total_pages": total_pages,
"results": [_user_payment_payload(request, item, status_names) for item in queryset[start : start + page_size]],
}
def _staff_required(user):
return bool(user and (user.is_staff or user.is_superuser))