DJANGO Phase 1
This commit is contained in:
@@ -34,6 +34,7 @@ class Igny8AdminSite(admin.AdminSite):
|
||||
'💰 Billing & Accounts': {
|
||||
'models': [
|
||||
('igny8_core_auth', 'Plan'),
|
||||
('billing', 'PlanLimitUsage'),
|
||||
('igny8_core_auth', 'Account'),
|
||||
('igny8_core_auth', 'Subscription'),
|
||||
('billing', 'Invoice'),
|
||||
|
||||
@@ -3,6 +3,7 @@ Billing Module Admin
|
||||
"""
|
||||
from django.contrib import admin
|
||||
from django.utils.html import format_html
|
||||
from django.contrib import messages
|
||||
from igny8_core.admin.base import AccountAdminMixin
|
||||
from igny8_core.business.billing.models import (
|
||||
CreditCostConfig,
|
||||
@@ -12,12 +13,28 @@ from igny8_core.business.billing.models import (
|
||||
PaymentMethodConfig,
|
||||
)
|
||||
from .models import CreditTransaction, CreditUsageLog, AccountPaymentMethod
|
||||
from import_export.admin import ExportMixin
|
||||
from import_export import resources
|
||||
from rangefilter.filters import DateRangeFilter
|
||||
|
||||
|
||||
from rangefilter.filters import DateRangeFilter
|
||||
|
||||
|
||||
class CreditTransactionResource(resources.ModelResource):
|
||||
"""Resource class for exporting Credit Transactions"""
|
||||
class Meta:
|
||||
model = CreditTransaction
|
||||
fields = ('id', 'account__name', 'transaction_type', 'amount', 'balance_after',
|
||||
'description', 'reference_id', 'created_at')
|
||||
export_order = fields
|
||||
|
||||
|
||||
@admin.register(CreditTransaction)
|
||||
class CreditTransactionAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
class CreditTransactionAdmin(ExportMixin, AccountAdminMixin, admin.ModelAdmin):
|
||||
resource_class = CreditTransactionResource
|
||||
list_display = ['id', 'account', 'transaction_type', 'amount', 'balance_after', 'description', 'created_at']
|
||||
list_filter = ['transaction_type', 'created_at', 'account']
|
||||
list_filter = ['transaction_type', ('created_at', DateRangeFilter), 'account']
|
||||
search_fields = ['description', 'account__name']
|
||||
readonly_fields = ['created_at']
|
||||
date_hierarchy = 'created_at'
|
||||
@@ -66,8 +83,18 @@ class InvoiceAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
|
||||
|
||||
class PaymentResource(resources.ModelResource):
|
||||
"""Resource class for exporting Payments"""
|
||||
class Meta:
|
||||
model = Payment
|
||||
fields = ('id', 'invoice__invoice_number', 'account__name', 'payment_method',
|
||||
'status', 'amount', 'currency', 'manual_reference', 'approved_by__email',
|
||||
'processed_at', 'created_at')
|
||||
export_order = fields
|
||||
|
||||
|
||||
@admin.register(Payment)
|
||||
class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
class PaymentAdmin(ExportMixin, AccountAdminMixin, admin.ModelAdmin):
|
||||
"""
|
||||
Main Payment Admin with approval workflow.
|
||||
When you change status to 'succeeded', it automatically:
|
||||
@@ -76,6 +103,7 @@ class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
- Activates account
|
||||
- Adds credits
|
||||
"""
|
||||
resource_class = PaymentResource
|
||||
list_display = [
|
||||
'id',
|
||||
'invoice',
|
||||
@@ -88,7 +116,7 @@ class PaymentAdmin(AccountAdminMixin, admin.ModelAdmin):
|
||||
'approved_by',
|
||||
'processed_at',
|
||||
]
|
||||
list_filter = ['status', 'payment_method', 'currency', 'created_at', 'processed_at']
|
||||
list_filter = ['status', 'payment_method', 'currency', ('created_at', DateRangeFilter), ('processed_at', DateRangeFilter)]
|
||||
search_fields = [
|
||||
'invoice__invoice_number',
|
||||
'account__name',
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
from django.contrib import admin
|
||||
from django.contrib import messages
|
||||
from igny8_core.admin.base import SiteSectorAdminMixin
|
||||
from .models import Tasks, Images, Content
|
||||
from igny8_core.business.content.models import ContentTaxonomy, ContentAttribute, ContentTaxonomyRelation, ContentClusterMap
|
||||
from import_export.admin import ExportMixin
|
||||
from import_export import resources
|
||||
|
||||
|
||||
class ContentTaxonomyInline(admin.TabularInline):
|
||||
@@ -13,13 +16,24 @@ class ContentTaxonomyInline(admin.TabularInline):
|
||||
verbose_name_plural = 'Taxonomy Terms (Tags & Categories)'
|
||||
|
||||
|
||||
class TaskResource(resources.ModelResource):
|
||||
"""Resource class for exporting Tasks"""
|
||||
class Meta:
|
||||
model = Tasks
|
||||
fields = ('id', 'title', 'description', 'status', 'content_type', 'content_structure',
|
||||
'site__name', 'sector__name', 'cluster__name', 'created_at', 'updated_at')
|
||||
export_order = fields
|
||||
|
||||
|
||||
@admin.register(Tasks)
|
||||
class TasksAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
class TasksAdmin(ExportMixin, SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
resource_class = TaskResource
|
||||
list_display = ['title', 'content_type', 'content_structure', 'site', 'sector', 'status', 'cluster', 'created_at']
|
||||
list_filter = ['status', 'content_type', 'content_structure', 'site', 'sector', 'cluster']
|
||||
search_fields = ['title', 'description']
|
||||
ordering = ['-created_at']
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
actions = ['bulk_set_status_draft', 'bulk_set_status_in_progress', 'bulk_set_status_completed']
|
||||
|
||||
fieldsets = (
|
||||
('Basic Info', {
|
||||
@@ -37,6 +51,24 @@ class TasksAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
}),
|
||||
)
|
||||
|
||||
def bulk_set_status_draft(self, request, queryset):
|
||||
"""Set selected tasks to draft status"""
|
||||
updated = queryset.update(status='draft')
|
||||
self.message_user(request, f'{updated} task(s) set to draft.', messages.SUCCESS)
|
||||
bulk_set_status_draft.short_description = 'Set status to Draft'
|
||||
|
||||
def bulk_set_status_in_progress(self, request, queryset):
|
||||
"""Set selected tasks to in-progress status"""
|
||||
updated = queryset.update(status='in_progress')
|
||||
self.message_user(request, f'{updated} task(s) set to in progress.', messages.SUCCESS)
|
||||
bulk_set_status_in_progress.short_description = 'Set status to In Progress'
|
||||
|
||||
def bulk_set_status_completed(self, request, queryset):
|
||||
"""Set selected tasks to completed status"""
|
||||
updated = queryset.update(status='completed')
|
||||
self.message_user(request, f'{updated} task(s) set to completed.', messages.SUCCESS)
|
||||
bulk_set_status_completed.short_description = 'Set status to Completed'
|
||||
|
||||
def get_site_display(self, obj):
|
||||
"""Safely get site name"""
|
||||
try:
|
||||
@@ -93,14 +125,26 @@ class ImagesAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
return '-'
|
||||
|
||||
|
||||
class ContentResource(resources.ModelResource):
|
||||
"""Resource class for exporting Content"""
|
||||
class Meta:
|
||||
model = Content
|
||||
fields = ('id', 'title', 'content_type', 'content_structure', 'status', 'source',
|
||||
'site__name', 'sector__name', 'cluster__name', 'word_count',
|
||||
'meta_title', 'meta_description', 'primary_keyword', 'external_url', 'created_at')
|
||||
export_order = fields
|
||||
|
||||
|
||||
@admin.register(Content)
|
||||
class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
class ContentAdmin(ExportMixin, SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
resource_class = ContentResource
|
||||
list_display = ['title', 'content_type', 'content_structure', 'site', 'sector', 'source', 'status', 'get_taxonomy_count', 'created_at']
|
||||
list_filter = ['content_type', 'content_structure', 'source', 'status', 'site', 'sector', 'created_at']
|
||||
search_fields = ['title', 'content_html', 'external_url']
|
||||
ordering = ['-created_at']
|
||||
readonly_fields = ['created_at', 'updated_at', 'word_count', 'get_tags_display', 'get_categories_display']
|
||||
inlines = [ContentTaxonomyInline]
|
||||
actions = ['bulk_set_status_published', 'bulk_set_status_draft']
|
||||
|
||||
fieldsets = (
|
||||
('Basic Info', {
|
||||
@@ -152,6 +196,18 @@ class ContentAdmin(SiteSectorAdminMixin, admin.ModelAdmin):
|
||||
return 'No categories'
|
||||
get_categories_display.short_description = 'Categories'
|
||||
|
||||
def bulk_set_status_published(self, request, queryset):
|
||||
"""Set selected content to published status"""
|
||||
updated = queryset.update(status='published')
|
||||
self.message_user(request, f'{updated} content item(s) set to published.', messages.SUCCESS)
|
||||
bulk_set_status_published.short_description = 'Set status to Published'
|
||||
|
||||
def bulk_set_status_draft(self, request, queryset):
|
||||
"""Set selected content to draft status"""
|
||||
updated = queryset.update(status='draft')
|
||||
self.message_user(request, f'{updated} content item(s) set to draft.', messages.SUCCESS)
|
||||
bulk_set_status_draft.short_description = 'Set status to Draft'
|
||||
|
||||
def get_site_display(self, obj):
|
||||
"""Safely get site name"""
|
||||
try:
|
||||
|
||||
@@ -36,16 +36,25 @@ ALLOWED_HOSTS = [
|
||||
]
|
||||
|
||||
INSTALLED_APPS = [
|
||||
# Django Admin Enhancements (must be before django.contrib.admin)
|
||||
'admin_interface',
|
||||
'colorfield',
|
||||
# Core Django apps
|
||||
'igny8_core.admin.apps.Igny8AdminConfig', # Custom admin config
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
# Third-party apps
|
||||
'rest_framework',
|
||||
'django_filters',
|
||||
'corsheaders',
|
||||
'drf_spectacular', # OpenAPI 3.0 schema generation
|
||||
'import_export',
|
||||
'rangefilter',
|
||||
'django_celery_results',
|
||||
# IGNY8 apps
|
||||
'igny8_core.auth.apps.Igny8CoreAuthConfig', # Use app config with custom label
|
||||
'igny8_core.ai.apps.AIConfig', # AI Framework
|
||||
'igny8_core.modules.planner.apps.PlannerConfig',
|
||||
@@ -591,6 +600,16 @@ LOGGING = {
|
||||
},
|
||||
}
|
||||
|
||||
# Admin Interface Configuration
|
||||
X_FRAME_OPTIONS = 'SAMEORIGIN' # Required for django-admin-interface
|
||||
|
||||
# Celery Results Backend
|
||||
CELERY_RESULT_BACKEND = 'django-db'
|
||||
CELERY_CACHE_BACKEND = 'django-cache'
|
||||
|
||||
# Import/Export Settings
|
||||
IMPORT_EXPORT_USE_TRANSACTIONS = True
|
||||
|
||||
# Billing / Payments configuration
|
||||
STRIPE_PUBLIC_KEY = os.getenv('STRIPE_PUBLIC_KEY', '')
|
||||
STRIPE_SECRET_KEY = os.getenv('STRIPE_SECRET_KEY', '')
|
||||
|
||||
Reference in New Issue
Block a user