783 lines
22 KiB
Python
783 lines
22 KiB
Python
"""
|
|
Inventory app admin configuration.
|
|
"""
|
|
|
|
from django.contrib import admin
|
|
from django.utils.html import format_html
|
|
from django.urls import reverse
|
|
from django.utils.safestring import mark_safe
|
|
from decimal import Decimal
|
|
from .models import (
|
|
InventoryItem, InventoryStock, InventoryLocation,
|
|
PurchaseOrder, PurchaseOrderItem, Supplier
|
|
)
|
|
|
|
|
|
class InventoryStockInline(admin.TabularInline):
|
|
"""
|
|
Inline admin for inventory stock.
|
|
"""
|
|
model = InventoryStock
|
|
extra = 0
|
|
fields = [
|
|
'location', 'lot_number', 'quantity_on_hand',
|
|
'quantity_reserved', 'expiration_date', 'quality_status'
|
|
]
|
|
readonly_fields = ['quantity_available']
|
|
|
|
|
|
class PurchaseOrderItemInline(admin.TabularInline):
|
|
"""
|
|
Inline admin for purchase order items.
|
|
"""
|
|
model = PurchaseOrderItem
|
|
extra = 0
|
|
fields = [
|
|
'line_number', 'inventory_item', 'quantity_ordered',
|
|
'quantity_received', 'unit_price', 'total_price'
|
|
]
|
|
readonly_fields = ['total_price', 'quantity_remaining']
|
|
|
|
|
|
@admin.register(InventoryItem)
|
|
class InventoryItemAdmin(admin.ModelAdmin):
|
|
"""
|
|
Admin interface for inventory items.
|
|
"""
|
|
list_display = [
|
|
'item_code', 'item_name', 'category', 'item_type',
|
|
'manufacturer', 'unit_cost', 'current_stock_display',
|
|
'reorder_point', 'needs_reorder_display', 'is_active'
|
|
]
|
|
list_filter = [
|
|
'tenant', 'category', 'item_type', 'manufacturer',
|
|
'is_active', 'is_tracked', 'has_expiration',
|
|
'controlled_substance'
|
|
]
|
|
search_fields = [
|
|
'item_code', 'item_name', 'description',
|
|
'manufacturer', 'model_number', 'part_number',
|
|
'upc_code', 'ndc_code'
|
|
]
|
|
readonly_fields = [
|
|
'item_id', 'current_stock', 'total_value', 'needs_reorder',
|
|
'created_at', 'updated_at'
|
|
]
|
|
fieldsets = [
|
|
('Item Information', {
|
|
'fields': [
|
|
'item_id', 'tenant', 'item_code', 'item_name', 'description'
|
|
]
|
|
}),
|
|
('Classification', {
|
|
'fields': [
|
|
'category', 'subcategory', 'item_type'
|
|
]
|
|
}),
|
|
('Manufacturer Information', {
|
|
'fields': [
|
|
'manufacturer', 'model_number', 'part_number'
|
|
]
|
|
}),
|
|
('Identification Codes', {
|
|
'fields': [
|
|
'upc_code', 'ndc_code', 'gtin_code'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Unit and Packaging', {
|
|
'fields': [
|
|
'unit_of_measure', 'package_size', 'package_type'
|
|
]
|
|
}),
|
|
('Pricing', {
|
|
'fields': [
|
|
'unit_cost', 'list_price'
|
|
]
|
|
}),
|
|
('Storage Requirements', {
|
|
'fields': [
|
|
'storage_temperature_min', 'storage_temperature_max',
|
|
'storage_humidity_min', 'storage_humidity_max',
|
|
'storage_requirements'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Expiration Information', {
|
|
'fields': [
|
|
'has_expiration', 'shelf_life_days'
|
|
]
|
|
}),
|
|
('Regulatory Information', {
|
|
'fields': [
|
|
'fda_approved', 'controlled_substance', 'dea_schedule'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Inventory Management', {
|
|
'fields': [
|
|
'is_active', 'is_tracked', 'is_serialized', 'is_lot_tracked'
|
|
]
|
|
}),
|
|
('Reorder Information', {
|
|
'fields': [
|
|
'reorder_point', 'reorder_quantity', 'min_stock_level', 'max_stock_level'
|
|
]
|
|
}),
|
|
('Supplier Information', {
|
|
'fields': [
|
|
'primary_supplier'
|
|
]
|
|
}),
|
|
('Clinical Information', {
|
|
'fields': [
|
|
'clinical_use', 'contraindications'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Stock Information', {
|
|
'fields': [
|
|
'current_stock', 'total_value', 'needs_reorder'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Notes', {
|
|
'fields': [
|
|
'notes'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Metadata', {
|
|
'fields': [
|
|
'created_at', 'updated_at', 'created_by'
|
|
],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
inlines = [InventoryStockInline]
|
|
date_hierarchy = 'created_at'
|
|
|
|
def current_stock_display(self, obj):
|
|
"""Display current stock with color coding."""
|
|
stock = obj.current_stock
|
|
if stock <= obj.reorder_point:
|
|
color = 'red'
|
|
elif stock <= obj.reorder_point * 1.5:
|
|
color = 'orange'
|
|
else:
|
|
color = 'green'
|
|
return format_html(
|
|
'<span style="color: {};">{}</span>',
|
|
color, stock
|
|
)
|
|
current_stock_display.short_description = 'Current Stock'
|
|
|
|
def needs_reorder_display(self, obj):
|
|
"""Display reorder status with icon."""
|
|
if obj.needs_reorder:
|
|
return format_html(
|
|
'<span style="color: red;">⚠️ Yes</span>'
|
|
)
|
|
return format_html(
|
|
'<span style="color: green;">✓ No</span>'
|
|
)
|
|
needs_reorder_display.short_description = 'Needs Reorder'
|
|
|
|
def get_queryset(self, request):
|
|
"""Filter by user's tenant."""
|
|
qs = super().get_queryset(request)
|
|
if hasattr(request.user, 'tenant'):
|
|
qs = qs.filter(tenant=request.user.tenant)
|
|
return qs.select_related('primary_supplier')
|
|
|
|
|
|
@admin.register(InventoryStock)
|
|
class InventoryStockAdmin(admin.ModelAdmin):
|
|
"""
|
|
Admin interface for inventory stock.
|
|
"""
|
|
list_display = [
|
|
'item_name', 'location_name', 'lot_number',
|
|
'quantity_on_hand', 'quantity_reserved', 'quantity_available',
|
|
'expiration_date', 'days_to_expiry_display', 'quality_status'
|
|
]
|
|
list_filter = [
|
|
'inventory_item__tenant', 'location', 'quality_status',
|
|
'expiration_date', 'received_date'
|
|
]
|
|
search_fields = [
|
|
'inventory_item__item_name', 'inventory_item__item_code',
|
|
'location__name', 'lot_number', 'serial_number'
|
|
]
|
|
readonly_fields = [
|
|
'stock_id', 'quantity_available', 'total_cost',
|
|
'tenant', 'is_expired', 'days_to_expiry',
|
|
'created_at', 'updated_at'
|
|
]
|
|
fieldsets = [
|
|
('Stock Information', {
|
|
'fields': [
|
|
'stock_id', 'inventory_item', 'location'
|
|
]
|
|
}),
|
|
('Lot Information', {
|
|
'fields': [
|
|
'lot_number', 'serial_number'
|
|
]
|
|
}),
|
|
('Quantity Information', {
|
|
'fields': [
|
|
'quantity_on_hand', 'quantity_reserved', 'quantity_available'
|
|
]
|
|
}),
|
|
('Dates', {
|
|
'fields': [
|
|
'received_date', 'expiration_date'
|
|
]
|
|
}),
|
|
('Cost Information', {
|
|
'fields': [
|
|
'unit_cost', 'total_cost'
|
|
]
|
|
}),
|
|
('Quality Information', {
|
|
'fields': [
|
|
'quality_status'
|
|
]
|
|
}),
|
|
('Supplier Information', {
|
|
'fields': [
|
|
'supplier', 'purchase_order'
|
|
]
|
|
}),
|
|
('Expiration Status', {
|
|
'fields': [
|
|
'is_expired', 'days_to_expiry'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Notes', {
|
|
'fields': [
|
|
'notes'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Related Information', {
|
|
'fields': [
|
|
'tenant'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Metadata', {
|
|
'fields': [
|
|
'created_at', 'updated_at'
|
|
],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
date_hierarchy = 'expiration_date'
|
|
|
|
def item_name(self, obj):
|
|
"""Display item name."""
|
|
return obj.inventory_item.item_name
|
|
item_name.short_description = 'Item'
|
|
|
|
def location_name(self, obj):
|
|
"""Display location name."""
|
|
return obj.location.name
|
|
location_name.short_description = 'Location'
|
|
|
|
def days_to_expiry_display(self, obj):
|
|
"""Display days to expiry with color coding."""
|
|
days = obj.days_to_expiry
|
|
if days is None:
|
|
return "-"
|
|
|
|
if days < 0:
|
|
color = 'red'
|
|
text = f"Expired {abs(days)} days ago"
|
|
elif days <= 30:
|
|
color = 'red'
|
|
text = f"{days} days"
|
|
elif days <= 90:
|
|
color = 'orange'
|
|
text = f"{days} days"
|
|
else:
|
|
color = 'green'
|
|
text = f"{days} days"
|
|
|
|
return format_html(
|
|
'<span style="color: {};">{}</span>',
|
|
color, text
|
|
)
|
|
days_to_expiry_display.short_description = 'Days to Expiry'
|
|
|
|
def get_queryset(self, request):
|
|
"""Filter by user's tenant."""
|
|
qs = super().get_queryset(request)
|
|
if hasattr(request.user, 'tenant'):
|
|
qs = qs.filter(inventory_item__tenant=request.user.tenant)
|
|
return qs.select_related('inventory_item', 'location', 'supplier')
|
|
|
|
|
|
@admin.register(InventoryLocation)
|
|
class InventoryLocationAdmin(admin.ModelAdmin):
|
|
"""
|
|
Admin interface for inventory locations.
|
|
"""
|
|
list_display = [
|
|
'location_code', 'name', 'location_type', 'building',
|
|
'floor', 'room', 'total_items_display', 'total_quantity_display',
|
|
'is_active'
|
|
]
|
|
list_filter = [
|
|
'tenant', 'location_type', 'building', 'floor',
|
|
'temperature_controlled', 'humidity_controlled',
|
|
'secure_location', 'is_active'
|
|
]
|
|
search_fields = [
|
|
'location_code', 'name', 'description',
|
|
'building', 'room', 'zone'
|
|
]
|
|
readonly_fields = [
|
|
'location_id', 'full_address', 'total_items', 'total_quantity',
|
|
'created_at', 'updated_at'
|
|
]
|
|
fieldsets = [
|
|
('Location Information', {
|
|
'fields': [
|
|
'location_id', 'tenant', 'location_code', 'name', 'description'
|
|
]
|
|
}),
|
|
('Location Type', {
|
|
'fields': [
|
|
'location_type'
|
|
]
|
|
}),
|
|
('Physical Information', {
|
|
'fields': [
|
|
'building', 'floor', 'room', 'zone', 'aisle', 'shelf', 'bin'
|
|
]
|
|
}),
|
|
('Capacity Information', {
|
|
'fields': [
|
|
'capacity_cubic_feet', 'max_weight_pounds'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Environmental Controls', {
|
|
'fields': [
|
|
'temperature_controlled', 'temperature_min', 'temperature_max',
|
|
'humidity_controlled', 'humidity_min', 'humidity_max'
|
|
]
|
|
}),
|
|
('Security and Access', {
|
|
'fields': [
|
|
'secure_location', 'access_control'
|
|
]
|
|
}),
|
|
('Location Status', {
|
|
'fields': [
|
|
'is_active'
|
|
]
|
|
}),
|
|
('Hierarchy', {
|
|
'fields': [
|
|
'parent_location'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Staff', {
|
|
'fields': [
|
|
'location_manager'
|
|
]
|
|
}),
|
|
('Summary Information', {
|
|
'fields': [
|
|
'full_address', 'total_items', 'total_quantity'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Notes', {
|
|
'fields': [
|
|
'notes'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Metadata', {
|
|
'fields': [
|
|
'created_at', 'updated_at', 'created_by'
|
|
],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
|
|
def total_items_display(self, obj):
|
|
"""Display total items count."""
|
|
return obj.total_items
|
|
total_items_display.short_description = 'Items'
|
|
|
|
def total_quantity_display(self, obj):
|
|
"""Display total quantity."""
|
|
return obj.total_quantity
|
|
total_quantity_display.short_description = 'Total Qty'
|
|
|
|
def get_queryset(self, request):
|
|
"""Filter by user's tenant."""
|
|
qs = super().get_queryset(request)
|
|
if hasattr(request.user, 'tenant'):
|
|
qs = qs.filter(tenant=request.user.tenant)
|
|
return qs.select_related('location_manager')
|
|
|
|
|
|
@admin.register(PurchaseOrder)
|
|
class PurchaseOrderAdmin(admin.ModelAdmin):
|
|
"""
|
|
Admin interface for purchase orders.
|
|
"""
|
|
list_display = [
|
|
'po_number', 'supplier_name', 'order_date',
|
|
'total_amount', 'status', 'requested_delivery_date',
|
|
'days_outstanding_display', 'is_overdue_display'
|
|
]
|
|
list_filter = [
|
|
'tenant', 'supplier', 'status', 'order_type',
|
|
'priority', 'order_date', 'requested_delivery_date'
|
|
]
|
|
search_fields = [
|
|
'po_number', 'supplier__name', 'supplier__supplier_code',
|
|
'notes'
|
|
]
|
|
readonly_fields = [
|
|
'po_id', 'po_number', 'total_amount',
|
|
'is_overdue', 'days_outstanding',
|
|
'created_at', 'updated_at'
|
|
]
|
|
fieldsets = [
|
|
('Purchase Order Information', {
|
|
'fields': [
|
|
'po_id', 'po_number', 'tenant'
|
|
]
|
|
}),
|
|
('Supplier Information', {
|
|
'fields': [
|
|
'supplier'
|
|
]
|
|
}),
|
|
('Order Dates', {
|
|
'fields': [
|
|
'order_date', 'requested_delivery_date',
|
|
'promised_delivery_date', 'actual_delivery_date'
|
|
]
|
|
}),
|
|
('Order Type and Priority', {
|
|
'fields': [
|
|
'order_type', 'priority'
|
|
]
|
|
}),
|
|
('Financial Information', {
|
|
'fields': [
|
|
'subtotal', 'tax_amount', 'shipping_amount', 'total_amount'
|
|
]
|
|
}),
|
|
('Order Status', {
|
|
'fields': [
|
|
'status'
|
|
]
|
|
}),
|
|
('Delivery Information', {
|
|
'fields': [
|
|
'delivery_location', 'delivery_instructions'
|
|
]
|
|
}),
|
|
('Payment Terms', {
|
|
'fields': [
|
|
'payment_terms'
|
|
]
|
|
}),
|
|
('Approval Information', {
|
|
'fields': [
|
|
'requested_by', 'approved_by', 'approval_date'
|
|
]
|
|
}),
|
|
('Status Information', {
|
|
'fields': [
|
|
'is_overdue', 'days_outstanding'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Notes', {
|
|
'fields': [
|
|
'notes'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Metadata', {
|
|
'fields': [
|
|
'created_at', 'updated_at', 'created_by'
|
|
],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
inlines = [PurchaseOrderItemInline]
|
|
date_hierarchy = 'order_date'
|
|
|
|
def supplier_name(self, obj):
|
|
"""Display supplier name."""
|
|
return obj.supplier.name
|
|
supplier_name.short_description = 'Supplier'
|
|
|
|
def days_outstanding_display(self, obj):
|
|
"""Display days outstanding with color coding."""
|
|
days = obj.days_outstanding
|
|
if days <= 7:
|
|
color = 'green'
|
|
elif days <= 30:
|
|
color = 'orange'
|
|
else:
|
|
color = 'red'
|
|
return format_html(
|
|
'<span style="color: {};">{} days</span>',
|
|
color, days
|
|
)
|
|
days_outstanding_display.short_description = 'Days Outstanding'
|
|
|
|
def is_overdue_display(self, obj):
|
|
"""Display overdue status with icon."""
|
|
if obj.is_overdue:
|
|
return format_html(
|
|
'<span style="color: red;">⚠️ Yes</span>'
|
|
)
|
|
return format_html(
|
|
'<span style="color: green;">✓ No</span>'
|
|
)
|
|
is_overdue_display.short_description = 'Overdue'
|
|
|
|
def get_queryset(self, request):
|
|
"""Filter by user's tenant."""
|
|
qs = super().get_queryset(request)
|
|
if hasattr(request.user, 'tenant'):
|
|
qs = qs.filter(tenant=request.user.tenant)
|
|
return qs.select_related('supplier', 'requested_by', 'approved_by')
|
|
|
|
|
|
@admin.register(PurchaseOrderItem)
|
|
class PurchaseOrderItemAdmin(admin.ModelAdmin):
|
|
"""
|
|
Admin interface for purchase order items.
|
|
"""
|
|
list_display = [
|
|
'po_number', 'line_number', 'item_name',
|
|
'quantity_ordered', 'quantity_received', 'quantity_remaining',
|
|
'unit_price', 'total_price', 'status'
|
|
]
|
|
list_filter = [
|
|
'purchase_order__tenant', 'status',
|
|
'purchase_order__order_date', 'requested_delivery_date'
|
|
]
|
|
search_fields = [
|
|
'purchase_order__po_number', 'inventory_item__item_name',
|
|
'inventory_item__item_code'
|
|
]
|
|
readonly_fields = [
|
|
'item_id', 'total_price', 'quantity_remaining',
|
|
'tenant', 'is_fully_received',
|
|
'created_at', 'updated_at'
|
|
]
|
|
fieldsets = [
|
|
('Item Information', {
|
|
'fields': [
|
|
'item_id', 'purchase_order', 'line_number'
|
|
]
|
|
}),
|
|
('Inventory Item', {
|
|
'fields': [
|
|
'inventory_item'
|
|
]
|
|
}),
|
|
('Quantity Information', {
|
|
'fields': [
|
|
'quantity_ordered', 'quantity_received', 'quantity_remaining'
|
|
]
|
|
}),
|
|
('Pricing Information', {
|
|
'fields': [
|
|
'unit_price', 'total_price'
|
|
]
|
|
}),
|
|
('Delivery Information', {
|
|
'fields': [
|
|
'requested_delivery_date'
|
|
]
|
|
}),
|
|
('Item Status', {
|
|
'fields': [
|
|
'status'
|
|
]
|
|
}),
|
|
('Status Information', {
|
|
'fields': [
|
|
'is_fully_received'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Notes', {
|
|
'fields': [
|
|
'notes'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Related Information', {
|
|
'fields': [
|
|
'tenant'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Metadata', {
|
|
'fields': [
|
|
'created_at', 'updated_at'
|
|
],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
|
|
def po_number(self, obj):
|
|
"""Display PO number."""
|
|
return obj.purchase_order.po_number
|
|
po_number.short_description = 'PO Number'
|
|
|
|
def item_name(self, obj):
|
|
"""Display item name."""
|
|
return obj.inventory_item.item_name
|
|
item_name.short_description = 'Item'
|
|
|
|
def get_queryset(self, request):
|
|
"""Filter by user's tenant."""
|
|
qs = super().get_queryset(request)
|
|
if hasattr(request.user, 'tenant'):
|
|
qs = qs.filter(purchase_order__tenant=request.user.tenant)
|
|
return qs.select_related('purchase_order', 'inventory_item')
|
|
|
|
|
|
@admin.register(Supplier)
|
|
class SupplierAdmin(admin.ModelAdmin):
|
|
"""
|
|
Admin interface for suppliers.
|
|
"""
|
|
list_display = [
|
|
'supplier_code', 'name', 'supplier_type', 'contact_person',
|
|
'phone', 'email', 'performance_rating_display',
|
|
'on_time_delivery_rate', 'is_active', 'is_preferred'
|
|
]
|
|
list_filter = [
|
|
'tenant', 'supplier_type', 'is_active', 'is_preferred',
|
|
'payment_terms', 'performance_rating'
|
|
]
|
|
search_fields = [
|
|
'supplier_code', 'name', 'contact_person',
|
|
'phone', 'email', 'city', 'state'
|
|
]
|
|
readonly_fields = [
|
|
'supplier_id', 'full_address', 'total_orders',
|
|
'total_order_value', 'has_active_contract',
|
|
'created_at', 'updated_at'
|
|
]
|
|
fieldsets = [
|
|
('Supplier Information', {
|
|
'fields': [
|
|
'supplier_id', 'tenant', 'supplier_code', 'name'
|
|
]
|
|
}),
|
|
('Supplier Type', {
|
|
'fields': [
|
|
'supplier_type'
|
|
]
|
|
}),
|
|
('Contact Information', {
|
|
'fields': [
|
|
'contact_person', 'phone', 'email', 'website'
|
|
]
|
|
}),
|
|
('Address Information', {
|
|
'fields': [
|
|
'address_line_1', 'address_line_2', 'city',
|
|
'state', 'postal_code', 'country'
|
|
]
|
|
}),
|
|
('Business Information', {
|
|
'fields': [
|
|
'tax_id', 'duns_number'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Payment Information', {
|
|
'fields': [
|
|
'payment_terms'
|
|
]
|
|
}),
|
|
('Performance Information', {
|
|
'fields': [
|
|
'performance_rating', 'on_time_delivery_rate', 'quality_rating'
|
|
]
|
|
}),
|
|
('Supplier Status', {
|
|
'fields': [
|
|
'is_active', 'is_preferred'
|
|
]
|
|
}),
|
|
('Certification Information', {
|
|
'fields': [
|
|
'certifications'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Contract Information', {
|
|
'fields': [
|
|
'contract_start_date', 'contract_end_date'
|
|
]
|
|
}),
|
|
('Summary Information', {
|
|
'fields': [
|
|
'full_address', 'total_orders', 'total_order_value',
|
|
'has_active_contract'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Notes', {
|
|
'fields': [
|
|
'notes'
|
|
],
|
|
'classes': ['collapse']
|
|
}),
|
|
('Metadata', {
|
|
'fields': [
|
|
'created_at', 'updated_at', 'created_by'
|
|
],
|
|
'classes': ['collapse']
|
|
})
|
|
]
|
|
|
|
def performance_rating_display(self, obj):
|
|
"""Display performance rating with stars."""
|
|
rating = obj.performance_rating
|
|
stars = '★' * int(rating) + '☆' * (5 - int(rating))
|
|
return format_html(
|
|
'<span title="{}/5">{}</span>',
|
|
rating, stars
|
|
)
|
|
performance_rating_display.short_description = 'Performance'
|
|
|
|
def get_queryset(self, request):
|
|
"""Filter by user's tenant."""
|
|
qs = super().get_queryset(request)
|
|
if hasattr(request.user, 'tenant'):
|
|
qs = qs.filter(tenant=request.user.tenant)
|
|
return qs
|
|
|
|
|
|
# Customize admin site
|
|
admin.site.site_header = "Hospital Management System - Inventory"
|
|
admin.site.site_title = "Inventory Admin"
|
|
admin.site.index_title = "Inventory Administration"
|
|
|