172 lines
5.3 KiB
Python
172 lines
5.3 KiB
Python
from django.contrib import admin
|
|
from django.utils.html import format_html
|
|
|
|
from .models import ProjectBrief, ProjectBriefAttachment, ProjectInternalNote
|
|
|
|
|
|
class ProjectBriefAttachmentInline(admin.TabularInline):
|
|
model = ProjectBriefAttachment
|
|
extra = 0
|
|
readonly_fields = ("original_filename", "file", "uploaded_at")
|
|
can_delete = True
|
|
|
|
|
|
class ProjectInternalNoteInline(admin.TabularInline):
|
|
model = ProjectInternalNote
|
|
extra = 1
|
|
fields = ("author", "note", "created_at")
|
|
readonly_fields = ("created_at",)
|
|
|
|
|
|
@admin.register(ProjectBrief)
|
|
class ProjectBriefAdmin(admin.ModelAdmin):
|
|
list_display = (
|
|
"title",
|
|
"client",
|
|
"category",
|
|
"status_badge",
|
|
"locked",
|
|
"show_on_website",
|
|
"budget_range",
|
|
"submitted_at",
|
|
)
|
|
list_filter = (
|
|
"status",
|
|
"category",
|
|
"budget_range",
|
|
"locked",
|
|
"show_on_website",
|
|
"submitted_at",
|
|
)
|
|
search_fields = (
|
|
"title",
|
|
"description",
|
|
"client__username",
|
|
"client__email",
|
|
"client__first_name",
|
|
"client__last_name",
|
|
)
|
|
readonly_fields = ("client", "submitted_at", "updated_at")
|
|
fieldsets = (
|
|
(
|
|
"Brief",
|
|
{
|
|
"fields": (
|
|
"client",
|
|
"title",
|
|
"category",
|
|
"description",
|
|
"budget_range",
|
|
"desired_deadline",
|
|
"reference_links",
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"Workflow",
|
|
{
|
|
"fields": (
|
|
"status",
|
|
"quote_text",
|
|
"website_notes",
|
|
"submitted_at",
|
|
"updated_at",
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"Client editing locks",
|
|
{
|
|
"description": (
|
|
"Lock individual fields so the client cannot change them while "
|
|
"the brief is still editable. 'Lock entire project' blocks all "
|
|
"client edits regardless of status."
|
|
),
|
|
"fields": (
|
|
"locked",
|
|
"lock_title",
|
|
"lock_category",
|
|
"lock_description",
|
|
"lock_budget_range",
|
|
"lock_desired_deadline",
|
|
"lock_reference_links",
|
|
"lock_attachments",
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"Website showcase",
|
|
{
|
|
"description": (
|
|
"Control whether this project appears on the public website and "
|
|
"which fields are visible on the website card."
|
|
),
|
|
"fields": (
|
|
"show_on_website",
|
|
"public_title",
|
|
"public_summary",
|
|
"public_tags",
|
|
"public_image",
|
|
"public_project_status",
|
|
"public_url",
|
|
),
|
|
},
|
|
),
|
|
(
|
|
"Website field visibility",
|
|
{
|
|
"description": (
|
|
"Each field can be independently shown or hidden on the website card."
|
|
),
|
|
"fields": (
|
|
"show_title_on_website",
|
|
"show_category_on_website",
|
|
"show_description_on_website",
|
|
"show_budget_on_website",
|
|
"show_deadline_on_website",
|
|
"show_references_on_website",
|
|
"show_attachments_on_website",
|
|
),
|
|
"classes": ("collapse",),
|
|
},
|
|
),
|
|
)
|
|
inlines = [ProjectBriefAttachmentInline, ProjectInternalNoteInline]
|
|
date_hierarchy = "submitted_at"
|
|
|
|
def save_formset(self, request, form, formset, change):
|
|
instances = formset.save(commit=False)
|
|
for instance in instances:
|
|
if isinstance(instance, ProjectInternalNote) and not instance.author_id:
|
|
instance.author = request.user
|
|
instance.save()
|
|
formset.save_m2m()
|
|
for obj in formset.deleted_objects:
|
|
obj.delete()
|
|
|
|
@admin.display(description="Status", boolean=False)
|
|
def status_badge(self, obj):
|
|
colors = {
|
|
ProjectBrief.STATUS_SUBMITTED: "#3b82f6",
|
|
ProjectBrief.STATUS_UNDER_REVIEW: "#8b5cf6",
|
|
ProjectBrief.STATUS_QUOTED: "#f59e0b",
|
|
ProjectBrief.STATUS_ACCEPTED: "#10b981",
|
|
ProjectBrief.STATUS_DECLINED: "#ef4444",
|
|
ProjectBrief.STATUS_IN_PROGRESS: "#06b6d4",
|
|
ProjectBrief.STATUS_DELIVERED: "#22c55e",
|
|
ProjectBrief.STATUS_CLOSED: "#6b7280",
|
|
}
|
|
color = colors.get(obj.status, "#6b7280")
|
|
return format_html(
|
|
'<span style="padding:2px 8px;border-radius:999px;background:{};color:#fff;font-size:12px;">{}</span>',
|
|
color,
|
|
obj.get_status_display(),
|
|
)
|
|
|
|
|
|
@admin.register(ProjectInternalNote)
|
|
class ProjectInternalNoteAdmin(admin.ModelAdmin):
|
|
list_display = ("brief", "author", "created_at")
|
|
search_fields = ("brief__title", "note", "author__username")
|
|
readonly_fields = ("created_at",)
|