from django.contrib import admin from . import models from orgs.models import Organization class OrgScopedAdmin(admin.ModelAdmin): """Limit queryset and FK choices to the current request.org when available.""" def get_queryset(self, request): qs = super().get_queryset(request) org = getattr(request, "org", None) if org is not None and any(f.name == "organization" for f in self.model._meta.fields): return qs.filter(organization=org) return qs def formfield_for_foreignkey(self, db_field, request, **kwargs): org = getattr(request, "org", None) if org is not None: # Direct organization field if db_field.name == "organization": kwargs["queryset"] = Organization.objects.filter(pk=org.pk) else: # If related model has an organization field, scope it rel = getattr(db_field, "remote_field", None) rel_model = getattr(rel, "model", None) if rel_model is not None and any(f.name == "organization" for f in rel_model._meta.fields): kwargs["queryset"] = rel_model.objects.filter(organization=org) return super().formfield_for_foreignkey(db_field, request, **kwargs) # Organization admin is managed in orgs app; UserProfile lives in orgs @admin.register(models.MaterialCategory) class MaterialCategoryAdmin(OrgScopedAdmin): list_display = ("name", "organization", "created_at") search_fields = ("name",) @admin.register(models.Material) class MaterialAdmin(OrgScopedAdmin): list_display = ("name", "code", "get_category_display", "organization", "default_unit") list_filter = ("default_unit", "category") search_fields = ("name", "code") class MaterialImageInline(admin.TabularInline): model = models.MaterialImage extra = 1 inlines = [MaterialImageInline] @admin.register(models.PriceList) class PriceListAdmin(OrgScopedAdmin): list_display = ("name", "organization", "currency_code", "effective_from", "effective_to") search_fields = ("name",) @admin.register(models.PriceListItem) class PriceListItemAdmin(admin.ModelAdmin): list_display = ("price_list", "material", "unit", "unit_price", "direction") list_filter = ("direction", "unit") search_fields = ("price_list__name", "material__name") @admin.register(models.Customer) class CustomerAdmin(OrgScopedAdmin): list_display = ("name", "organization", "email", "phone", "price_list") search_fields = ("name", "email", "phone") @admin.register(models.CustomerSite) class CustomerSiteAdmin(OrgScopedAdmin): list_display = ("name", "customer") search_fields = ("name", "customer__name") @admin.register(models.ServiceAgreement) class ServiceAgreementAdmin(OrgScopedAdmin): list_display = ("customer", "site", "price_list", "valid_from", "valid_to") search_fields = ("customer__name",) @admin.register(models.PickupOrder) class PickupOrderAdmin(OrgScopedAdmin): list_display = ("id", "organization", "customer", "site", "status", "scheduled_at") list_filter = ("status",) search_fields = ("customer__name", "site__name") @admin.register(models.PickupItem) class PickupItemAdmin(OrgScopedAdmin): list_display = ("pickup", "material", "estimated_qty", "unit") search_fields = ("pickup__id", "material__name") @admin.register(models.WeighTicket) class WeighTicketAdmin(OrgScopedAdmin): list_display = ("id", "pickup", "ticket_number", "net_weight", "unit", "recorded_at") search_fields = ("ticket_number", "pickup__id") @admin.register(models.WeighLine) class WeighLineAdmin(OrgScopedAdmin): list_display = ("ticket", "material", "quantity", "unit") search_fields = ("ticket__id", "material__name") """Billing models are registered in billing.admin.""" @admin.register(models.Document) class DocumentAdmin(OrgScopedAdmin): list_display = ("organization", "kind", "content_type", "object_id", "uploaded_by", "created_at") search_fields = ("kind",) @admin.register(models.AuditLog) class AuditLogAdmin(OrgScopedAdmin): list_display = ("created_at", "organization", "user", "action", "content_type", "object_id") search_fields = ("action", "user__username") list_filter = ("action",) @admin.register(models.ScrapListing) class ScrapListingAdmin(OrgScopedAdmin): list_display = ("id", "organization", "title", "status", "starts_at", "ends_at", "is_public") list_filter = ("status", "is_public") search_fields = ("title",) @admin.register(models.ScrapListingItem) class ScrapListingItemAdmin(OrgScopedAdmin): list_display = ("listing", "material", "quantity_estimate", "unit") search_fields = ("listing__id", "material__name") @admin.register(models.ScrapBid) class ScrapBidAdmin(OrgScopedAdmin): list_display = ("listing", "bidder_org", "price_total", "status", "created_at") list_filter = ("status",) search_fields = ("listing__id", "bidder_org__code") @admin.register(models.ScrapAward) class ScrapAwardAdmin(OrgScopedAdmin): list_display = ("listing", "winning_bid", "pickup") search_fields = ("listing__id",) @admin.register(models.ScrapListingInvite) class ScrapListingInviteAdmin(OrgScopedAdmin): list_display = ("listing", "invited_org", "invited_user", "created_at") search_fields = ("listing__id", "invited_org__code", "invited_user__username") @admin.register(models.ProvidedService) class ProvidedServiceAdmin(OrgScopedAdmin): list_display = ("title", "organization", "is_enabled", "display_order", "created_at") list_filter = ("organization", "is_enabled") search_fields = ("title", "description") ordering = ("organization", "display_order", "id")