billing and paymetn methods

This commit is contained in:
IGNY8 VPS (Salman)
2025-12-07 04:28:46 +00:00
parent 31c06d032c
commit 4e764e208d
11 changed files with 1010 additions and 349 deletions

View File

@@ -40,8 +40,6 @@ class Igny8AdminSite(admin.AdminSite):
('billing', 'Invoice'),
('billing', 'Payment'),
('billing', 'CreditPackage'),
('billing', 'PaymentMethodConfig'),
('billing', 'AccountPaymentMethod'),
('billing', 'CreditCostConfig'),
],
},
@@ -107,6 +105,12 @@ class Igny8AdminSite(admin.AdminSite):
('automation', 'AutomationRun'),
],
},
'Payments': {
'models': [
('billing', 'PaymentMethodConfig'),
('billing', 'AccountPaymentMethod'),
],
},
'Integrations & Sync': {
'models': [
('integration', 'SiteIntegration'),
@@ -170,6 +174,7 @@ class Igny8AdminSite(admin.AdminSite):
'Writer Module',
'Thinker Module',
'System Configuration',
'Payments',
'Integrations & Sync',
'Publishing',
'Optimization',

View File

@@ -545,6 +545,179 @@ class AdminBillingViewSet(viewsets.ViewSet):
status=status.HTTP_400_BAD_REQUEST
)
@action(detail=False, methods=['get', 'post'])
def payment_method_configs(self, request):
"""List/create payment method configs (country-level)"""
error = self._require_admin(request)
if error:
return error
class PMConfigSerializer(serializers.ModelSerializer):
class Meta:
model = PaymentMethodConfig
fields = [
'id',
'country_code',
'payment_method',
'display_name',
'is_enabled',
'instructions',
'sort_order',
'created_at',
'updated_at',
]
read_only_fields = ['id', 'created_at', 'updated_at']
if request.method.lower() == 'post':
serializer = PMConfigSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
return Response(PMConfigSerializer(obj).data, status=status.HTTP_201_CREATED)
qs = PaymentMethodConfig.objects.all().order_by('country_code', 'sort_order', 'payment_method')
country = request.query_params.get('country_code')
method = request.query_params.get('payment_method')
if country:
qs = qs.filter(country_code=country)
if method:
qs = qs.filter(payment_method=method)
data = PMConfigSerializer(qs, many=True).data
return Response({'results': data, 'count': len(data)})
@action(detail=True, methods=['get', 'patch', 'put', 'delete'], url_path='payment_method_config')
@extend_schema(tags=['Admin Billing'])
def payment_method_config(self, request, pk=None):
"""Retrieve/update/delete a payment method config"""
error = self._require_admin(request)
if error:
return error
obj = get_object_or_404(PaymentMethodConfig, id=pk)
class PMConfigSerializer(serializers.ModelSerializer):
class Meta:
model = PaymentMethodConfig
fields = [
'id',
'country_code',
'payment_method',
'display_name',
'is_enabled',
'instructions',
'sort_order',
'created_at',
'updated_at',
]
read_only_fields = ['id', 'created_at', 'updated_at']
if request.method.lower() == 'get':
return Response(PMConfigSerializer(obj).data)
if request.method.lower() in ['patch', 'put']:
partial = request.method.lower() == 'patch'
serializer = PMConfigSerializer(obj, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
return Response(PMConfigSerializer(obj).data)
# delete
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@action(detail=False, methods=['get', 'post'])
@extend_schema(tags=['Admin Billing'])
def account_payment_methods(self, request):
"""List/create account payment methods (admin)"""
error = self._require_admin(request)
if error:
return error
class AccountPMSerializer(serializers.ModelSerializer):
class Meta:
model = AccountPaymentMethod
fields = [
'id',
'account',
'type',
'display_name',
'is_default',
'is_enabled',
'is_verified',
'country_code',
'instructions',
'metadata',
'created_at',
'updated_at',
]
read_only_fields = ['id', 'is_verified', 'created_at', 'updated_at']
if request.method.lower() == 'post':
serializer = AccountPMSerializer(data=request.data)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
return Response(AccountPMSerializer(obj).data, status=status.HTTP_201_CREATED)
qs = AccountPaymentMethod.objects.select_related('account').order_by('account_id', '-is_default', 'display_name')
account_id = request.query_params.get('account_id')
if account_id:
qs = qs.filter(account_id=account_id)
data = AccountPMSerializer(qs, many=True).data
return Response({'results': data, 'count': len(data)})
@action(detail=True, methods=['get', 'patch', 'put', 'delete'], url_path='account_payment_method')
@extend_schema(tags=['Admin Billing'])
def account_payment_method(self, request, pk=None):
"""Retrieve/update/delete an account payment method (admin)"""
error = self._require_admin(request)
if error:
return error
obj = get_object_or_404(AccountPaymentMethod, id=pk)
class AccountPMSerializer(serializers.ModelSerializer):
class Meta:
model = AccountPaymentMethod
fields = [
'id',
'account',
'type',
'display_name',
'is_default',
'is_enabled',
'is_verified',
'country_code',
'instructions',
'metadata',
'created_at',
'updated_at',
]
read_only_fields = ['id', 'is_verified', 'created_at', 'updated_at']
if request.method.lower() == 'get':
return Response(AccountPMSerializer(obj).data)
if request.method.lower() in ['patch', 'put']:
partial = request.method.lower() == 'patch'
serializer = AccountPMSerializer(obj, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
obj = serializer.save()
if serializer.validated_data.get('is_default'):
AccountPaymentMethod.objects.filter(account=obj.account).exclude(id=obj.id).update(is_default=False)
return Response(AccountPMSerializer(obj).data)
obj.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
@action(detail=True, methods=['post'], url_path='account_payment_method/set_default')
@extend_schema(tags=['Admin Billing'])
def set_default_account_payment_method(self, request, pk=None):
"""Set default account payment method (admin)"""
error = self._require_admin(request)
if error:
return error
obj = get_object_or_404(AccountPaymentMethod, id=pk)
AccountPaymentMethod.objects.filter(account=obj.account).update(is_default=False)
obj.is_default = True
obj.save(update_fields=['is_default'])
return Response({'message': 'Default payment method updated', 'id': obj.id})
@action(detail=False, methods=['get'])
def stats(self, request):
"""System billing stats"""

View File

@@ -94,9 +94,10 @@ class CreditPackageAdmin(admin.ModelAdmin):
@admin.register(PaymentMethodConfig)
class PaymentMethodConfigAdmin(admin.ModelAdmin):
list_display = ['country_code', 'payment_method', 'is_enabled', 'display_name', 'sort_order']
list_display = ['country_code', 'payment_method', 'display_name', 'is_enabled', 'sort_order', 'updated_at']
list_filter = ['payment_method', 'is_enabled', 'country_code']
search_fields = ['country_code', 'display_name', 'payment_method']
list_editable = ['is_enabled', 'sort_order']
readonly_fields = ['created_at', 'updated_at']

View File

@@ -19,6 +19,21 @@ urlpatterns = [
path('billing/pending_payments/', BillingAdminViewSet.as_view({'get': 'pending_payments'}), name='admin-billing-pending-payments'),
path('billing/<int:pk>/approve_payment/', BillingAdminViewSet.as_view({'post': 'approve_payment'}), name='admin-billing-approve-payment'),
path('billing/<int:pk>/reject_payment/', BillingAdminViewSet.as_view({'post': 'reject_payment'}), name='admin-billing-reject-payment'),
path('billing/payment-method-configs/', BillingAdminViewSet.as_view({'get': 'payment_method_configs', 'post': 'payment_method_configs'}), name='admin-billing-payment-method-configs'),
path('billing/payment-method-configs/<int:pk>/', BillingAdminViewSet.as_view({
'get': 'payment_method_config',
'patch': 'payment_method_config',
'put': 'payment_method_config',
'delete': 'payment_method_config',
}), name='admin-billing-payment-method-config'),
path('billing/account-payment-methods/', BillingAdminViewSet.as_view({'get': 'account_payment_methods', 'post': 'account_payment_methods'}), name='admin-billing-account-payment-methods'),
path('billing/account-payment-methods/<int:pk>/', BillingAdminViewSet.as_view({
'get': 'account_payment_method',
'patch': 'account_payment_method',
'put': 'account_payment_method',
'delete': 'account_payment_method',
}), name='admin-billing-account-payment-method'),
path('billing/account-payment-methods/<int:pk>/set_default/', BillingAdminViewSet.as_view({'post': 'set_default_account_payment_method'}), name='admin-billing-account-payment-method-set-default'),
]
urlpatterns += router.urls