81 lines
3.0 KiB
Python
81 lines
3.0 KiB
Python
from decimal import Decimal, InvalidOperation
|
|
|
|
from django.db import transaction
|
|
from django.db.models import Sum
|
|
from rest_framework import status
|
|
from rest_framework.decorators import api_view, permission_classes
|
|
from rest_framework.permissions import IsAuthenticated
|
|
from rest_framework.response import Response
|
|
|
|
from apps.common.api import get_current_team
|
|
|
|
from .models import CreditAccount, CreditLedger
|
|
from .serializers import CreditAccountSerializer, CreditLedgerSerializer
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def summary(request):
|
|
team = get_current_team(request.user)
|
|
account, _ = CreditAccount.objects.get_or_create(team=team)
|
|
charged = CreditLedger.objects.filter(team=team, ledger_type=CreditLedger.Type.CHARGE).aggregate(
|
|
total=Sum("amount")
|
|
)["total"] or 0
|
|
return Response(
|
|
{
|
|
"account": CreditAccountSerializer(account).data,
|
|
"charged_total": charged,
|
|
}
|
|
)
|
|
|
|
|
|
@api_view(["GET"])
|
|
@permission_classes([IsAuthenticated])
|
|
def ledgers(request):
|
|
team = get_current_team(request.user)
|
|
queryset = CreditLedger.objects.filter(team=team).select_related("user", "project", "task").order_by("-created_at")
|
|
project_id = request.query_params.get("project")
|
|
user_id = request.query_params.get("user")
|
|
if project_id:
|
|
queryset = queryset.filter(project_id=project_id)
|
|
if user_id:
|
|
queryset = queryset.filter(user_id=user_id)
|
|
return Response(CreditLedgerSerializer(queryset[:100], many=True).data)
|
|
|
|
|
|
@api_view(["POST"])
|
|
@permission_classes([IsAuthenticated])
|
|
def recharge(request):
|
|
team = get_current_team(request.user)
|
|
try:
|
|
amount = Decimal(str(request.data.get("amount", "0")))
|
|
bonus = Decimal(str(request.data.get("bonus", "0")))
|
|
except (InvalidOperation, TypeError):
|
|
return Response({"detail": "invalid amount"}, status=status.HTTP_400_BAD_REQUEST)
|
|
if amount <= 0:
|
|
return Response({"detail": "amount must be positive"}, status=status.HTTP_400_BAD_REQUEST)
|
|
if bonus < 0:
|
|
return Response({"detail": "bonus cannot be negative"}, status=status.HTTP_400_BAD_REQUEST)
|
|
channel = str(request.data.get("channel") or "manual")[:32]
|
|
credited = amount + bonus
|
|
with transaction.atomic():
|
|
account, _ = CreditAccount.objects.select_for_update().get_or_create(team=team)
|
|
account.balance += credited
|
|
account.save(update_fields=["balance", "updated_at"])
|
|
ledger = CreditLedger.objects.create(
|
|
team=team,
|
|
user=request.user,
|
|
ledger_type=CreditLedger.Type.RECHARGE,
|
|
amount=credited,
|
|
balance_after=account.balance,
|
|
reason="团队充值",
|
|
metadata={"channel": channel, "paid_amount": str(amount), "bonus": str(bonus)},
|
|
)
|
|
return Response(
|
|
{
|
|
"account": CreditAccountSerializer(account).data,
|
|
"ledger": CreditLedgerSerializer(ledger).data,
|
|
},
|
|
status=status.HTTP_201_CREATED,
|
|
)
|