Phase 6: Financials & Payouts — 4 new financial endpoints (metrics, transactions, settlements, release)
This commit is contained in:
@@ -27,4 +27,8 @@ urlpatterns = [
|
||||
path('events/', views.EventListView.as_view(), name='event-list'),
|
||||
path('events/<int:pk>/', views.EventDetailView.as_view(), name='event-detail'),
|
||||
path('events/<int:pk>/moderate/', views.EventModerationView.as_view(), name='event-moderate'),
|
||||
path('financials/metrics/', views.FinancialMetricsView.as_view(), name='financial-metrics'),
|
||||
path('financials/transactions/', views.TransactionListView.as_view(), name='transaction-list'),
|
||||
path('financials/settlements/', views.SettlementListView.as_view(), name='settlement-list'),
|
||||
path('financials/settlements/<int:pk>/release/', views.SettlementReleaseView.as_view(), name='settlement-release'),
|
||||
]
|
||||
|
||||
@@ -717,3 +717,127 @@ class EventModerationView(APIView):
|
||||
return Response({'error': 'Invalid action'}, status=400)
|
||||
e.refresh_from_db()
|
||||
return Response(_serialize_event(e))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Phase 6: Financials & Payouts
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
_TX_STATUS_MAP = {
|
||||
'captured': 'Completed',
|
||||
'created': 'Pending',
|
||||
'failed': 'Failed',
|
||||
'refunded': 'Failed',
|
||||
}
|
||||
|
||||
def _serialize_transaction(t):
|
||||
ts = t.captured_at or t.created_at
|
||||
order_ref = getattr(t, 'razorpay_order_id', None) or getattr(t, 'transaction_id', None)
|
||||
return {
|
||||
'id': str(t.id),
|
||||
'title': f'Payment {order_ref}' if order_ref else f'Transaction #{t.id}',
|
||||
'partner': '',
|
||||
'amount': t.amount / 100,
|
||||
'date': ts.isoformat() if ts else '',
|
||||
'type': 'in',
|
||||
'method': 'Razorpay',
|
||||
'fees': 0,
|
||||
'net': t.amount / 100,
|
||||
'status': _TX_STATUS_MAP.get(t.status, 'Pending'),
|
||||
}
|
||||
|
||||
_SETTLEMENT_STATUS_MAP = {
|
||||
'pending': 'Ready',
|
||||
'failed': 'Overdue',
|
||||
'cancelled': 'Overdue',
|
||||
'completed': 'On Hold',
|
||||
'refunded': 'On Hold',
|
||||
}
|
||||
|
||||
def _serialize_settlement(p):
|
||||
return {
|
||||
'id': str(p.id),
|
||||
'partnerName': '',
|
||||
'eventName': '',
|
||||
'amount': float(p.payment_transaction_amount),
|
||||
'dueDate': p.payment_transaction_date.isoformat() if p.payment_transaction_date else '',
|
||||
'status': _SETTLEMENT_STATUS_MAP.get(p.payment_transaction_status, 'On Hold'),
|
||||
}
|
||||
|
||||
|
||||
class FinancialMetricsView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
from ledger.models import RazorpayTransaction
|
||||
from banking_operations.models import PaymentTransaction
|
||||
from django.db.models import Sum
|
||||
|
||||
total_paise = (
|
||||
RazorpayTransaction.objects.filter(status='captured')
|
||||
.aggregate(t=Sum('amount'))['t'] or 0
|
||||
)
|
||||
total_revenue = total_paise / 100
|
||||
|
||||
total_payouts = float(
|
||||
PaymentTransaction.objects
|
||||
.filter(payment_type='debit', payment_transaction_status='completed')
|
||||
.aggregate(t=Sum('payment_transaction_amount'))['t'] or 0
|
||||
)
|
||||
platform_earnings = round(total_revenue * 0.12, 2)
|
||||
|
||||
pending_count = PaymentTransaction.objects.filter(
|
||||
payment_type='debit', payment_transaction_status='pending'
|
||||
).count()
|
||||
pending_amount = float(
|
||||
PaymentTransaction.objects
|
||||
.filter(payment_type='debit', payment_transaction_status='pending')
|
||||
.aggregate(t=Sum('payment_transaction_amount'))['t'] or 0
|
||||
)
|
||||
|
||||
return Response({
|
||||
'totalRevenue': total_revenue,
|
||||
'totalPayouts': total_payouts,
|
||||
'platformEarnings': platform_earnings,
|
||||
'pendingPayouts': pending_count,
|
||||
'pendingPayoutAmount': pending_amount,
|
||||
})
|
||||
|
||||
|
||||
class TransactionListView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
from ledger.models import RazorpayTransaction
|
||||
try:
|
||||
page = max(1, int(request.GET.get('page', 1)))
|
||||
page_size = min(100, int(request.GET.get('page_size', 20)))
|
||||
except (ValueError, TypeError):
|
||||
page, page_size = 1, 20
|
||||
qs = RazorpayTransaction.objects.order_by('-id')
|
||||
total = qs.count()
|
||||
txs = qs[(page - 1) * page_size: page * page_size]
|
||||
return Response({'count': total, 'results': [_serialize_transaction(t) for t in txs]})
|
||||
|
||||
|
||||
class SettlementListView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request):
|
||||
from banking_operations.models import PaymentTransaction
|
||||
qs = PaymentTransaction.objects.filter(
|
||||
payment_type='debit'
|
||||
).order_by('-id')[:50]
|
||||
return Response([_serialize_settlement(p) for p in qs])
|
||||
|
||||
|
||||
class SettlementReleaseView(APIView):
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def post(self, request, pk):
|
||||
from banking_operations.models import PaymentTransaction
|
||||
from django.shortcuts import get_object_or_404
|
||||
p = get_object_or_404(PaymentTransaction, pk=pk, payment_type='debit')
|
||||
p.payment_transaction_status = 'completed'
|
||||
p.save(update_fields=['payment_transaction_status'])
|
||||
return Response(_serialize_settlement(p))
|
||||
|
||||
Reference in New Issue
Block a user