Marwan Alwali 4d06ca4b5e update
2025-09-20 14:26:19 +03:00

449 lines
21 KiB
Python

from django import forms
from django.core.exceptions import ValidationError
from django.utils import timezone
from decimal import Decimal
from .models import *
from accounts.models import User
class BuildingForm(forms.ModelForm):
"""Form for managing buildings"""
class Meta:
model = Building
fields = [
'name', 'code', 'building_type', 'address',
'floor_count', 'total_area_sqm', 'construction_year',
'architect', 'contractor', 'facility_manager',
'last_major_renovation', 'is_active'
]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'code': forms.TextInput(attrs={'class': 'form-control'}),
'building_type': forms.Select(attrs={'class': 'form-select'}),
'airport_code': forms.TextInput(attrs={'class': 'form-control'}),
'address': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'floor_count': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'total_area_sqm': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'construction_year': forms.NumberInput(attrs={'class': 'form-control', 'min': '1900', 'max': '2030'}),
'architect': forms.TextInput(attrs={'class': 'form-control'}),
'contractor': forms.TextInput(attrs={'class': 'form-control'}),
'facility_manager': forms.Select(attrs={'class': 'form-select'}),
'last_major_renovation': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def clean_construction_year(self):
year = self.cleaned_data.get('construction_year')
if year and year > timezone.now().year:
raise ValidationError('Construction year cannot be in the future.')
return year
class FloorForm(forms.ModelForm):
"""Form for managing floors"""
class Meta:
model = Floor
fields = [
'building', 'floor_number', 'name', 'area_sqm',
'ceiling_height_m', 'is_public_access'
]
widgets = {
'building': forms.Select(attrs={'class': 'form-select'}),
'floor_number': forms.NumberInput(attrs={'class': 'form-control'}),
'name': forms.TextInput(attrs={'class': 'form-control'}),
'area_sqm': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'ceiling_height_m': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'is_public_access': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['building'].queryset = Building.objects.filter(is_active=True)
class RoomForm(forms.ModelForm):
"""Form for managing rooms"""
class Meta:
model = Room
fields = [
'floor', 'room_number', 'name', 'room_type', 'area_sqm',
'capacity', 'occupancy_status', 'is_accessible', 'current_tenant',
'lease_start_date', 'lease_end_date', 'monthly_rent',
'has_hvac', 'has_electrical', 'has_plumbing', 'has_internet', 'notes'
]
widgets = {
'floor': forms.Select(attrs={'class': 'form-select'}),
'room_number': forms.TextInput(attrs={'class': 'form-control'}),
'name': forms.TextInput(attrs={'class': 'form-control'}),
'room_type': forms.Select(attrs={'class': 'form-select'}),
'area_sqm': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'capacity': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'occupancy_status': forms.Select(attrs={'class': 'form-select'}),
'is_accessible': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'current_tenant': forms.TextInput(attrs={'class': 'form-control'}),
'lease_start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'lease_end_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'monthly_rent': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'has_hvac': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'has_electrical': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'has_plumbing': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'has_internet': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
}
def clean(self):
cleaned_data = super().clean()
lease_start = cleaned_data.get('lease_start_date')
lease_end = cleaned_data.get('lease_end_date')
if lease_start and lease_end and lease_start >= lease_end:
raise ValidationError('Lease end date must be after lease start date.')
return cleaned_data
class AssetCategoryForm(forms.ModelForm):
"""Form for managing asset categories"""
class Meta:
model = AssetCategory
fields = ['name', 'code', 'description', 'parent_category', 'is_active']
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'code': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'parent_category': forms.Select(attrs={'class': 'form-select'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Exclude self from parent category choices
if self.instance.pk:
self.fields['parent_category'].queryset = AssetCategory.objects.exclude(pk=self.instance.pk)
class AssetForm(forms.ModelForm):
"""Form for managing assets"""
class Meta:
model = Asset
fields = [
'asset_id', 'name', 'category', 'building', 'floor', 'room',
'location_description', 'manufacturer', 'model', 'serial_number',
'purchase_date', 'purchase_cost', 'current_value', 'depreciation_rate',
'warranty_start_date', 'warranty_end_date', 'service_provider',
'service_contract_number', 'status', 'condition',
'last_inspection_date', 'next_maintenance_date', 'assigned_to', 'notes'
]
widgets = {
'asset_id': forms.TextInput(attrs={'class': 'form-control'}),
'name': forms.TextInput(attrs={'class': 'form-control'}),
'category': forms.Select(attrs={'class': 'form-select'}),
'building': forms.Select(attrs={'class': 'form-select'}),
'floor': forms.Select(attrs={'class': 'form-select'}),
'room': forms.Select(attrs={'class': 'form-select'}),
'location_description': forms.TextInput(attrs={'class': 'form-control'}),
'manufacturer': forms.TextInput(attrs={'class': 'form-control'}),
'model': forms.TextInput(attrs={'class': 'form-control'}),
'serial_number': forms.TextInput(attrs={'class': 'form-control'}),
'purchase_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'purchase_cost': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'current_value': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'depreciation_rate': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0', 'max': '100'}),
'warranty_start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'warranty_end_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'service_provider': forms.TextInput(attrs={'class': 'form-control'}),
'service_contract_number': forms.TextInput(attrs={'class': 'form-control'}),
'status': forms.Select(attrs={'class': 'form-select'}),
'condition': forms.Select(attrs={'class': 'form-select'}),
'last_inspection_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'next_maintenance_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'assigned_to': forms.Select(attrs={'class': 'form-select'}),
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['category'].queryset = AssetCategory.objects.filter(is_active=True)
self.fields['building'].queryset = Building.objects.filter(is_active=True)
self.fields['floor'].required = False
self.fields['room'].required = False
def clean(self):
cleaned_data = super().clean()
warranty_start = cleaned_data.get('warranty_start_date')
warranty_end = cleaned_data.get('warranty_end_date')
purchase_date = cleaned_data.get('purchase_date')
purchase_cost = cleaned_data.get('purchase_cost')
current_value = cleaned_data.get('current_value')
if warranty_start and warranty_end and warranty_start >= warranty_end:
raise ValidationError('Warranty end date must be after warranty start date.')
if purchase_date and warranty_start and warranty_start < purchase_date:
raise ValidationError('Warranty start date cannot be before purchase date.')
if purchase_cost and current_value and current_value > purchase_cost:
raise ValidationError('Current value cannot be greater than purchase cost.')
return cleaned_data
class MaintenanceRequestForm(forms.ModelForm):
"""Form for creating maintenance requests"""
class Meta:
model = MaintenanceRequest
fields = [
'title', 'description', 'maintenance_type', 'building',
'floor', 'room', 'asset', 'priority', 'scheduled_date', 'actual_cost',
'estimated_cost', 'notes', 'assigned_to', 'scheduled_date', 'estimated_hours', 'status',
]
widgets = {
'title': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
'maintenance_type': forms.Select(attrs={'class': 'form-select'}),
'building': forms.Select(attrs={'class': 'form-select'}),
'floor': forms.Select(attrs={'class': 'form-select'}),
'room': forms.Select(attrs={'class': 'form-select'}),
'asset': forms.Select(attrs={'class': 'form-select'}),
'priority': forms.Select(attrs={'class': 'form-select'}),
'scheduled_date': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}),
'estimated_cost': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'assigned_to': forms.Select(attrs={'class': 'form-select'}),
'estimated_hours': forms.NumberInput(attrs={'class': 'form-control', 'type': 'number'}),
'status': forms.Select(attrs={'class': 'form-select'}),
'actual_cost': forms.NumberInput(attrs={'class': 'form-control', 'type': 'number'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['maintenance_type'].queryset = MaintenanceType.objects.filter(is_active=True)
self.fields['building'].queryset = Building.objects.filter(is_active=True)
self.fields['floor'].required = False
self.fields['room'].required = False
self.fields['asset'].required = False
class MaintenanceUpdateForm(forms.ModelForm):
"""Form for updating maintenance requests"""
class Meta:
model = MaintenanceRequest
fields = [
'status', 'assigned_to', 'scheduled_date', 'started_date',
'completed_date', 'actual_cost', 'completion_notes'
]
widgets = {
'status': forms.Select(attrs={'class': 'form-select'}),
'assigned_to': forms.Select(attrs={'class': 'form-select'}),
'scheduled_date': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}),
'started_date': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}),
'completed_date': forms.DateTimeInput(attrs={'class': 'form-control', 'type': 'datetime-local'}),
'actual_cost': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'completion_notes': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
}
def clean(self):
cleaned_data = super().clean()
scheduled_date = cleaned_data.get('scheduled_date')
started_date = cleaned_data.get('started_date')
completed_date = cleaned_data.get('completed_date')
if started_date and scheduled_date and started_date < scheduled_date:
raise ValidationError('Start date cannot be before scheduled date.')
if completed_date and started_date and completed_date < started_date:
raise ValidationError('Completion date cannot be before start date.')
return cleaned_data
class MaintenanceScheduleForm(forms.ModelForm):
"""Form for creating maintenance schedules"""
class Meta:
model = MaintenanceSchedule
fields = [
'name', 'description', 'maintenance_type', 'asset', 'building',
'room', 'frequency', 'frequency_interval', 'start_date',
'end_date', 'assigned_to', 'estimated_duration_hours', 'is_active'
]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'maintenance_type': forms.Select(attrs={'class': 'form-select'}),
'asset': forms.Select(attrs={'class': 'form-select'}),
'building': forms.Select(attrs={'class': 'form-select'}),
'room': forms.Select(attrs={'class': 'form-select'}),
'frequency': forms.Select(attrs={'class': 'form-select'}),
'frequency_interval': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
'start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'end_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'assigned_to': forms.Select(attrs={'class': 'form-select'}),
'estimated_duration_hours': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.5', 'min': '0'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['maintenance_type'].queryset = MaintenanceType.objects.filter(is_active=True)
self.fields['asset'].required = False
self.fields['building'].required = False
self.fields['room'].required = False
def clean(self):
cleaned_data = super().clean()
start_date = cleaned_data.get('start_date')
end_date = cleaned_data.get('end_date')
asset = cleaned_data.get('asset')
building = cleaned_data.get('building')
room = cleaned_data.get('room')
if start_date and end_date and start_date >= end_date:
raise ValidationError('End date must be after start date.')
# At least one scope must be specified
if not any([asset, building, room]):
raise ValidationError('Please specify at least one scope: asset, building, or room.')
return cleaned_data
class VendorForm(forms.ModelForm):
"""Form for managing vendors"""
class Meta:
model = Vendor
fields = [
'name', 'vendor_type', 'contact_person', 'email', 'phone',
'address', 'license_number', 'insurance_policy',
'insurance_expiry', 'rating', 'is_active'
]
widgets = {
'name': forms.TextInput(attrs={'class': 'form-control'}),
'vendor_type': forms.Select(attrs={'class': 'form-select'}),
'contact_person': forms.TextInput(attrs={'class': 'form-control'}),
'email': forms.EmailInput(attrs={'class': 'form-control'}),
'phone': forms.TextInput(attrs={'class': 'form-control'}),
'address': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'license_number': forms.TextInput(attrs={'class': 'form-control'}),
'insurance_policy': forms.TextInput(attrs={'class': 'form-control'}),
'insurance_expiry': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'rating': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.1', 'min': '0', 'max': '5'}),
'is_active': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
}
class ServiceContractForm(forms.ModelForm):
"""Form for managing service contracts"""
class Meta:
model = ServiceContract
fields = [
'contract_number', 'vendor', 'title', 'description',
'start_date', 'end_date', 'contract_value', 'payment_terms',
'buildings', 'service_areas', 'auto_renewal', 'renewal_notice_days'
]
widgets = {
'contract_number': forms.TextInput(attrs={'class': 'form-control'}),
'vendor': forms.Select(attrs={'class': 'form-select'}),
'title': forms.TextInput(attrs={'class': 'form-control'}),
'description': forms.Textarea(attrs={'class': 'form-control', 'rows': 4}),
'start_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'end_date': forms.DateInput(attrs={'class': 'form-control', 'type': 'date'}),
'contract_value': forms.NumberInput(attrs={'class': 'form-control', 'step': '0.01', 'min': '0'}),
'payment_terms': forms.TextInput(attrs={'class': 'form-control'}),
'buildings': forms.CheckboxSelectMultiple(),
'service_areas': forms.Textarea(attrs={'class': 'form-control', 'rows': 3}),
'auto_renewal': forms.CheckboxInput(attrs={'class': 'form-check-input'}),
'renewal_notice_days': forms.NumberInput(attrs={'class': 'form-control', 'min': '1'}),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['vendor'].queryset = Vendor.objects.filter(is_active=True)
self.fields['buildings'].queryset = Building.objects.filter(is_active=True)
def clean(self):
cleaned_data = super().clean()
start_date = cleaned_data.get('start_date')
end_date = cleaned_data.get('end_date')
if start_date and end_date and start_date >= end_date:
raise ValidationError('End date must be after start date.')
return cleaned_data
class FacilitySearchForm(forms.Form):
"""Form for searching facilities"""
search_query = forms.CharField(
max_length=100,
required=False,
widget=forms.TextInput(attrs={
'class': 'form-control',
'placeholder': 'Search buildings, rooms, assets...'
})
)
building = forms.ModelChoiceField(
queryset=Building.objects.filter(is_active=True),
required=False,
empty_label="All Buildings",
widget=forms.Select(attrs={'class': 'form-select'})
)
asset_category = forms.ModelChoiceField(
queryset=AssetCategory.objects.filter(is_active=True),
required=False,
empty_label="All Categories",
widget=forms.Select(attrs={'class': 'form-select'})
)
class MaintenanceFilterForm(forms.Form):
"""Form for filtering maintenance requests"""
STATUS_CHOICES = [('', 'All Statuses')] + MaintenanceRequest.MaintenanceStatus.choices
PRIORITY_CHOICES = [('', 'All Priorities')] + MaintenanceRequest.Priority.choices
status = forms.ChoiceField(
choices=STATUS_CHOICES,
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
priority = forms.ChoiceField(
choices=PRIORITY_CHOICES,
required=False,
widget=forms.Select(attrs={'class': 'form-select'})
)
building = forms.ModelChoiceField(
queryset=Building.objects.filter(is_active=True),
required=False,
empty_label="All Buildings",
widget=forms.Select(attrs={'class': 'form-select'})
)
assigned_to = forms.ModelChoiceField(
queryset=None, # Will be set in __init__
required=False,
empty_label="All Assignees",
widget=forms.Select(attrs={'class': 'form-select'})
)
date_from = forms.DateField(
required=False,
widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
)
date_to = forms.DateField(
required=False,
widget=forms.DateInput(attrs={'class': 'form-control', 'type': 'date'})
)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.fields['assigned_to'].queryset = User.objects.filter(is_active=True)