feat: add portal account records
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
from django.contrib import messages
|
||||
from django.contrib.auth.mixins import LoginRequiredMixin
|
||||
from django.db.models import Sum
|
||||
from django.shortcuts import get_object_or_404, redirect
|
||||
from django.urls import reverse_lazy
|
||||
from django.views import View
|
||||
from django.views.generic import FormView, TemplateView
|
||||
|
||||
from apps.billing.models import PointsLedger, RechargeOrder
|
||||
from apps.billing.services import get_balance_snapshot
|
||||
from apps.users.models import ApiKey
|
||||
|
||||
@@ -12,6 +14,58 @@ from .forms import ApiKeyCreateForm
|
||||
|
||||
|
||||
NEW_API_KEY_SESSION_KEY = "portal_new_api_key"
|
||||
RECORDS_PAGE_SIZE = 50
|
||||
|
||||
|
||||
def _sum_or_zero(queryset, field_name: str):
|
||||
return queryset.aggregate(total=Sum(field_name))["total"] or 0
|
||||
|
||||
|
||||
def get_portal_account_summary(user) -> dict:
|
||||
paid_orders = RechargeOrder.objects.filter(
|
||||
user=user,
|
||||
status=RechargeOrder.Status.PAID,
|
||||
)
|
||||
consume_entries = PointsLedger.objects.filter(
|
||||
user=user,
|
||||
change_type=PointsLedger.ChangeType.CONSUME,
|
||||
)
|
||||
refund_entries = PointsLedger.objects.filter(
|
||||
user=user,
|
||||
change_type=PointsLedger.ChangeType.REFUND,
|
||||
)
|
||||
recharge_entries = PointsLedger.objects.filter(
|
||||
user=user,
|
||||
change_type=PointsLedger.ChangeType.RECHARGE,
|
||||
)
|
||||
consumed_points = abs(int(_sum_or_zero(consume_entries, "points_delta")))
|
||||
refunded_points = int(_sum_or_zero(refund_entries, "points_delta"))
|
||||
return {
|
||||
"recharge_total_amount": _sum_or_zero(paid_orders, "amount_money"),
|
||||
"recharge_points_total": int(_sum_or_zero(recharge_entries, "points_delta")),
|
||||
"consumed_points_total": consumed_points,
|
||||
"refunded_points_total": refunded_points,
|
||||
"net_used_points": consumed_points - refunded_points,
|
||||
"paid_recharge_count": paid_orders.count(),
|
||||
}
|
||||
|
||||
|
||||
def get_recharge_orders_for_user(user):
|
||||
return RechargeOrder.objects.filter(user=user).order_by("-created_at", "-id")
|
||||
|
||||
|
||||
def get_usage_ledger_entries_for_user(user):
|
||||
return (
|
||||
PointsLedger.objects.filter(
|
||||
user=user,
|
||||
change_type__in=(
|
||||
PointsLedger.ChangeType.CONSUME,
|
||||
PointsLedger.ChangeType.REFUND,
|
||||
),
|
||||
)
|
||||
.select_related("ref_call", "ref_call__api_key")
|
||||
.order_by("-created_at", "-id")
|
||||
)
|
||||
|
||||
|
||||
class DashboardView(LoginRequiredMixin, TemplateView):
|
||||
@@ -20,6 +74,13 @@ class DashboardView(LoginRequiredMixin, TemplateView):
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["balance"] = get_balance_snapshot(self.request.user)
|
||||
context.update(get_portal_account_summary(self.request.user))
|
||||
context["recent_recharge_orders"] = get_recharge_orders_for_user(
|
||||
self.request.user
|
||||
)[:5]
|
||||
context["recent_usage_entries"] = get_usage_ledger_entries_for_user(
|
||||
self.request.user
|
||||
)[:5]
|
||||
return context
|
||||
|
||||
|
||||
@@ -57,3 +118,25 @@ class ApiKeyDeleteView(LoginRequiredMixin, View):
|
||||
api_key.save(update_fields=("status", "updated_at"))
|
||||
messages.success(request, "API Key 已删除")
|
||||
return redirect("portal-apikeys")
|
||||
|
||||
|
||||
class RechargeRecordListView(LoginRequiredMixin, TemplateView):
|
||||
template_name = "portal/recharge_records.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
orders = get_recharge_orders_for_user(self.request.user)
|
||||
context.update(get_portal_account_summary(self.request.user))
|
||||
context["recharge_orders"] = orders[:RECORDS_PAGE_SIZE]
|
||||
return context
|
||||
|
||||
|
||||
class UsageRecordListView(LoginRequiredMixin, TemplateView):
|
||||
template_name = "portal/usage_records.html"
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
entries = get_usage_ledger_entries_for_user(self.request.user)
|
||||
context.update(get_portal_account_summary(self.request.user))
|
||||
context["usage_entries"] = entries[:RECORDS_PAGE_SIZE]
|
||||
return context
|
||||
|
||||
Reference in New Issue
Block a user