from django.contrib import admin from core.models import ( Customer, CustomerAddress, CustomerContact, Account, AccountAddress, AccountContact, Service, Project, Report, Revenue, Labor, Schedule, Invoice, AccountPunchlist, ProjectPunchlist, CustomerProfile, TeamProfile, Scope, Area, Task, TaskCompletion, ScopeTemplate, AreaTemplate, TaskTemplate, ProjectScope, ProjectScopeCategory, ProjectScopeTask, ProjectScopeTaskCompletion, ProjectScopeTemplate, ProjectAreaTemplate, ProjectTaskTemplate, ServiceSession, ProjectSession, ServiceSessionNote, ProjectSessionNote, # Events & Notifications Event, NotificationRule, Notification, NotificationDelivery, # Messaging Conversation, ConversationParticipant, Message, MessageReadReceipt, # Session Media ServiceSessionImage, ProjectSessionImage, ServiceSessionVideo, ProjectSessionVideo, # Chat ChatConversation, ChatMessage, ) @admin.register(Customer) class CustomerAdmin(admin.ModelAdmin): list_display = ("name", "status", "start_date", "end_date") list_filter = ("status",) search_fields = ("name",) @admin.register(Account) class AccountAdmin(admin.ModelAdmin): list_display = ("name", "customer", "status", "start_date", "end_date") list_filter = ("status", "customer") search_fields = ("name", "customer__name") @admin.register(CustomerAddress) class CustomerAddressAdmin(admin.ModelAdmin): list_display = ("customer", "address_type", "is_primary", "is_active") list_filter = ("address_type", "is_primary", "is_active") search_fields = ("customer__name", "street_address", "city") @admin.register(CustomerContact) class CustomerContactAdmin(admin.ModelAdmin): list_display = ("full_name", "customer", "email", "phone", "is_primary", "is_active") list_filter = ("is_primary", "is_active") search_fields = ("first_name", "last_name", "customer__name", "email", "phone") @admin.register(AccountAddress) class AccountAddressAdmin(admin.ModelAdmin): list_display = ("account", "street_address", "city", "is_primary", "is_active") list_filter = ("is_primary", "is_active") search_fields = ("account__name", "street_address", "city") @admin.register(AccountContact) class AccountContactAdmin(admin.ModelAdmin): list_display = ("full_name", "account", "email", "phone", "is_primary", "is_active") list_filter = ("is_primary", "is_active") search_fields = ("first_name", "last_name", "account__name", "email", "phone") @admin.register(Service) class ServiceAdmin(admin.ModelAdmin): list_display = ("account_address", "date", "status") list_filter = ("status", "date") search_fields = ("account_address__account__name",) @admin.register(Project) class ProjectAdmin(admin.ModelAdmin): list_display = ("customer", "account_address", "date", "status", "labor", "amount") list_filter = ("status", "date", "customer") search_fields = ( "customer__name", "account_address__account__name", "street_address", "city", "state", "zip_code", ) @admin.register(Report) class ReportAdmin(admin.ModelAdmin): list_display = ("team_member", "date") list_filter = ("date",) search_fields = ("team_member__first_name", "team_member__last_name") @admin.register(Revenue) class RevenueAdmin(admin.ModelAdmin): list_display = ("account", "amount", "start_date", "end_date") list_filter = ("start_date",) search_fields = ("account__name",) @admin.register(Labor) class LaborAdmin(admin.ModelAdmin): list_display = ("account_address", "amount", "start_date", "end_date") list_filter = ("start_date",) search_fields = ("account_address__account__name",) @admin.register(Schedule) class ScheduleAdmin(admin.ModelAdmin): list_display = ("account_address", "start_date", "end_date", "weekend_service") list_filter = ("weekend_service",) search_fields = ("account_address__account__name",) @admin.register(Invoice) class InvoiceAdmin(admin.ModelAdmin): list_display = ("customer", "date", "status", "date_paid", "payment_type") list_filter = ("status", "date") search_fields = ("customer__name",) @admin.register(AccountPunchlist) class AccountPunchlistAdmin(admin.ModelAdmin): list_display = ("account", "date") list_filter = ("date",) search_fields = ("account__name",) @admin.register(ProjectPunchlist) class ProjectPunchlistAdmin(admin.ModelAdmin): list_display = ("project", "date") list_filter = ("date",) search_fields = ( "project__account_address__account__name", "project__street_address", "project__city", "project__state", "project__zip_code", "project__customer__name", ) @admin.register(CustomerProfile) class CustomerProfileAdmin(admin.ModelAdmin): list_display = ("user", "get_customers", "status") list_filter = ("status",) search_fields = ("user__username", "first_name", "last_name", "email") filter_horizontal = ("customers",) def get_customers(self, obj): """Display comma-separated list of customers""" return ", ".join([c.name for c in obj.customers.all()]) get_customers.short_description = "Customers" @admin.register(TeamProfile) class TeamProfileAdmin(admin.ModelAdmin): list_display = ("user", "first_name", "last_name", "status") list_filter = ("status",) search_fields = ("user__username", "first_name", "last_name") @admin.register(Scope) class ScopeAdmin(admin.ModelAdmin): list_display = ("name", "account", "account_address", "is_active") list_filter = ("is_active", "account") search_fields = ("name", "account__name", "account_address__street_address") class TaskTemplateInline(admin.TabularInline): model = TaskTemplate extra = 1 fields = ("description", "frequency", "order", "is_conditional", "estimated_minutes") ordering = ("order",) show_change_link = True class AreaTemplateInline(admin.TabularInline): model = AreaTemplate extra = 1 fields = ("name", "order") ordering = ("order",) show_change_link = True @admin.register(ScopeTemplate) class ScopeTemplateAdmin(admin.ModelAdmin): list_display = ("name", "is_active") list_filter = ("is_active",) search_fields = ("name", "description") inlines = (AreaTemplateInline,) ordering = ("name",) @admin.register(AreaTemplate) class AreaTemplateAdmin(admin.ModelAdmin): list_display = ("name", "scope_template", "order") list_filter = ("scope_template",) search_fields = ("name", "scope_template__name") inlines = (TaskTemplateInline,) ordering = ("scope_template", "order", "name") @admin.register(TaskTemplate) class TaskTemplateAdmin(admin.ModelAdmin): list_display = ("short_description", "area_template", "frequency", "order", "is_conditional") list_filter = ("frequency", "is_conditional", "area_template__scope_template") search_fields = ("description", "area_template__name", "area_template__scope_template__name") ordering = ("area_template", "order") def short_description(self, obj): return (obj.description or "")[:60] short_description.short_description = "Description" @admin.register(ServiceSession) class ServiceSessionAdmin(admin.ModelAdmin): list_display = ( "service", "account", "account_address", "scope", "start", "end", "created_by", "closed_by", "is_active", ) list_filter = ("start", "end", "account", "scope") search_fields = ( "service__account_address__account__name", "account_address__street_address", "account_address__city", "created_by__first_name", "created_by__last_name", ) ordering = ("-start",) readonly_fields = ("duration_seconds",) filter_horizontal = ("completed_tasks",) @admin.register(ProjectScope) class ProjectScopeAdmin(admin.ModelAdmin): list_display = ("name", "project", "account", "account_address", "is_active") list_filter = ("is_active", "project", "account") search_fields = ( "name", "project__customer__name", "project__account_address__account__name", "account__name", "account_address__street_address", ) ordering = ("name",) @admin.register(ProjectScopeCategory) class ProjectScopeCategoryAdmin(admin.ModelAdmin): list_display = ("name", "scope", "order") list_filter = ("scope",) search_fields = ("name", "scope__name") ordering = ("scope", "order", "name") @admin.register(ProjectScopeTask) class ProjectScopeTaskAdmin(admin.ModelAdmin): list_display = ("short_description", "category", "order", "estimated_minutes") list_filter = ("category__scope",) search_fields = ("description", "category__name", "category__scope__name") ordering = ("category", "order") def short_description(self, obj): return (obj.description or "")[:60] short_description.short_description = "Description" class ProjectTaskTemplateInline(admin.TabularInline): model = ProjectTaskTemplate extra = 1 fields = ("description", "order", "estimated_minutes") ordering = ("order",) show_change_link = True class ProjectAreaTemplateInline(admin.TabularInline): model = ProjectAreaTemplate extra = 1 fields = ("name", "order") ordering = ("order",) show_change_link = True @admin.register(ProjectScopeTemplate) class ProjectScopeTemplateAdmin(admin.ModelAdmin): list_display = ("name", "is_active") list_filter = ("is_active",) search_fields = ("name", "description") inlines = (ProjectAreaTemplateInline,) ordering = ("name",) @admin.register(ProjectAreaTemplate) class ProjectAreaTemplateAdmin(admin.ModelAdmin): list_display = ("name", "scope_template", "order") list_filter = ("scope_template",) search_fields = ("name", "scope_template__name") inlines = (ProjectTaskTemplateInline,) ordering = ("scope_template", "order", "name") @admin.register(ProjectTaskTemplate) class ProjectTaskTemplateAdmin(admin.ModelAdmin): list_display = ("short_description", "area_template", "order", "estimated_minutes") list_filter = ("area_template__scope_template",) search_fields = ("description", "area_template__name", "area_template__scope_template__name") ordering = ("area_template", "order") def short_description(self, obj): return (obj.description or "")[:60] short_description.short_description = "Description" @admin.register(ProjectSession) class ProjectSessionAdmin(admin.ModelAdmin): list_display = ( "project", "account", "account_address", "scope", "start", "end", "created_by", "closed_by", "is_active", ) list_filter = ("start", "end", "account", "scope") search_fields = ( "project__account_address__account__name", "account_address__street_address", "account_address__city", "created_by__first_name", "created_by__last_name", ) ordering = ("-start",) readonly_fields = ("duration_seconds",) # Admin registrations for Area, Task, TaskCompletion, and ProjectScopeTaskCompletion class TaskInline(admin.TabularInline): model = Task extra = 1 fields = ("description", "frequency", "order", "is_conditional", "estimated_minutes") ordering = ("order",) show_change_link = True @admin.register(Area) class AreaAdmin(admin.ModelAdmin): list_display = ("name", "scope", "order") list_filter = ("scope",) search_fields = ("name", "scope__name") ordering = ("scope", "order", "name") inlines = (TaskInline,) @admin.register(Task) class TaskAdmin(admin.ModelAdmin): list_display = ("short_description", "area", "frequency", "order", "is_conditional") list_filter = ("frequency", "is_conditional", "area__scope") search_fields = ("description", "area__name", "area__scope__name") ordering = ("area", "order") def short_description(self, obj): return (obj.description or "")[:60] short_description.short_description = "Description" @admin.register(TaskCompletion) class TaskCompletionAdmin(admin.ModelAdmin): list_display = ("task", "service", "account_address", "completed_by", "completed_at", "year", "month") list_filter = ("completed_at", "completed_by", "task__area__scope") search_fields = ( "task__description", "task__area__name", "task__area__scope__name", "service__account_address__account__name", "service__account_address__street_address", ) ordering = ("-completed_at",) @admin.register(ProjectScopeTaskCompletion) class ProjectScopeTaskCompletionAdmin(admin.ModelAdmin): list_display = ( "task", "project", "account", "account_address", "completed_by", "completed_at", ) list_filter = ("completed_at", "completed_by", "task__category__scope", "project", "account") search_fields = ( "task__description", "task__category__name", "task__category__scope__name", "project__customer__name", "project__account_address__account__name", "account__name", "account_address__street_address", ) ordering = ("-completed_at",) @admin.register(ServiceSessionNote) class ServiceSessionNoteAdmin(admin.ModelAdmin): list_display = ("session", "short_content", "author", "internal", "created_at") list_filter = ("internal", "created_at", "author") search_fields = ( "content", "session__service__account_address__account__name", "author__first_name", "author__last_name", ) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") def short_content(self, obj): return (obj.content or "")[:60] short_content.short_description = "Content" @admin.register(ProjectSessionNote) class ProjectSessionNoteAdmin(admin.ModelAdmin): list_display = ("session", "short_content", "author", "internal", "created_at") list_filter = ("internal", "created_at", "author") search_fields = ( "content", "session__project__customer__name", "author__first_name", "author__last_name", ) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") def short_content(self, obj): return (obj.content or "")[:60] short_content.short_description = "Content" # ============================================================================= # Events & Notifications # ============================================================================= @admin.register(Event) class EventAdmin(admin.ModelAdmin): list_display = ("event_type", "entity_type", "entity_id", "created_at") list_filter = ("event_type", "entity_type", "created_at") search_fields = ("entity_type", "entity_id") ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") @admin.register(NotificationRule) class NotificationRuleAdmin(admin.ModelAdmin): list_display = ("name", "is_active", "get_channels", "created_at") list_filter = ("is_active",) search_fields = ("name", "description") filter_horizontal = ("target_team_profiles", "target_customer_profiles") readonly_fields = ("created_at", "updated_at") def get_channels(self, obj): return ", ".join(obj.channels) if obj.channels else "" get_channels.short_description = "Channels" @admin.register(Notification) class NotificationAdmin(admin.ModelAdmin): list_display = ("subject", "event", "status", "read_at", "created_at") list_filter = ("status", "created_at") search_fields = ("subject", "body") ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") @admin.register(NotificationDelivery) class NotificationDeliveryAdmin(admin.ModelAdmin): list_display = ("notification", "channel", "status", "attempts", "sent_at") list_filter = ("channel", "status") ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") # ============================================================================= # Messaging # ============================================================================= @admin.register(Conversation) class ConversationAdmin(admin.ModelAdmin): list_display = ("subject", "conversation_type", "last_message_at", "is_archived") list_filter = ("conversation_type", "is_archived") search_fields = ("subject",) ordering = ("-last_message_at",) readonly_fields = ("created_at", "updated_at") @admin.register(ConversationParticipant) class ConversationParticipantAdmin(admin.ModelAdmin): list_display = ("conversation", "unread_count", "is_muted", "is_archived", "joined_at") list_filter = ("is_muted", "is_archived") ordering = ("-joined_at",) readonly_fields = ("created_at", "updated_at") @admin.register(Message) class MessageAdmin(admin.ModelAdmin): list_display = ("conversation", "short_body", "is_system_message", "created_at") list_filter = ("is_system_message", "created_at") search_fields = ("body",) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") def short_body(self, obj): return (obj.body or "")[:60] short_body.short_description = "Body" @admin.register(MessageReadReceipt) class MessageReadReceiptAdmin(admin.ModelAdmin): list_display = ("message", "read_at") ordering = ("-read_at",) readonly_fields = ("created_at", "updated_at") # ============================================================================= # Session Media # ============================================================================= @admin.register(ServiceSessionImage) class ServiceSessionImageAdmin(admin.ModelAdmin): list_display = ("service_session", "title", "created_at") list_filter = ("created_at",) search_fields = ("title",) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") @admin.register(ProjectSessionImage) class ProjectSessionImageAdmin(admin.ModelAdmin): list_display = ("project_session", "title", "created_at") list_filter = ("created_at",) search_fields = ("title",) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") @admin.register(ServiceSessionVideo) class ServiceSessionVideoAdmin(admin.ModelAdmin): list_display = ("service_session", "title", "duration_seconds", "created_at") list_filter = ("created_at",) search_fields = ("title",) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") @admin.register(ProjectSessionVideo) class ProjectSessionVideoAdmin(admin.ModelAdmin): list_display = ("project_session", "title", "duration_seconds", "created_at") list_filter = ("created_at",) search_fields = ("title",) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") # ============================================================================= # Chat # ============================================================================= @admin.register(ChatConversation) class ChatConversationAdmin(admin.ModelAdmin): list_display = ("team_profile", "title", "is_active", "created_at", "updated_at") list_filter = ("is_active", "created_at") search_fields = ("title", "team_profile__first_name", "team_profile__last_name") ordering = ("-updated_at",) readonly_fields = ("created_at", "updated_at") @admin.register(ChatMessage) class ChatMessageAdmin(admin.ModelAdmin): list_display = ("conversation", "role", "short_content", "created_at") list_filter = ("role", "created_at") search_fields = ("content",) ordering = ("-created_at",) readonly_fields = ("created_at", "updated_at") def short_content(self, obj): return (obj.content or "")[:60] short_content.short_description = "Content"