221 lines
8.9 KiB
Python
221 lines
8.9 KiB
Python
from django import forms
|
|
from django.core.exceptions import ValidationError
|
|
from .models import InstallationReport
|
|
from wells.models import WaterMeterManufacturer
|
|
|
|
|
|
class InstallationReportForm(forms.ModelForm):
|
|
# Additional fields for manufacturer handling
|
|
new_manufacturer = forms.CharField(
|
|
max_length=100,
|
|
required=False,
|
|
widget=forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'placeholder': 'شرکت سازنده جدید',
|
|
'style': 'display:none;'
|
|
})
|
|
)
|
|
|
|
class Meta:
|
|
model = InstallationReport
|
|
fields = [
|
|
'visited_date', 'new_water_meter_serial', 'seal_number',
|
|
'utm_x', 'utm_y', 'meter_type', 'meter_size',
|
|
'discharge_pipe_diameter', 'usage_type', 'exploitation_license_number',
|
|
'motor_power', 'pre_calibration_flow_rate', 'post_calibration_flow_rate',
|
|
'water_meter_manufacturer', 'sim_number', 'driving_force',
|
|
'is_meter_suspicious', 'description'
|
|
]
|
|
|
|
widgets = {
|
|
'visited_date': forms.DateInput(attrs={
|
|
'type': 'date',
|
|
'class': 'form-control',
|
|
'required': True
|
|
}),
|
|
'new_water_meter_serial': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'required': True
|
|
}),
|
|
'seal_number': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'required': True
|
|
}),
|
|
'utm_x': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'step': '1',
|
|
'required': True
|
|
}),
|
|
'utm_y': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'step': '1',
|
|
'required': True
|
|
}),
|
|
'meter_type': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}, choices=[
|
|
('', 'انتخاب کنید'),
|
|
('smart', 'هوشمند (آب و برق)'),
|
|
('volumetric', 'حجمی')
|
|
]),
|
|
'meter_size': forms.TextInput(attrs={
|
|
'class': 'form-control'
|
|
}),
|
|
'discharge_pipe_diameter': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': '0',
|
|
'step': '1',
|
|
'required': True
|
|
}),
|
|
'usage_type': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'required': True
|
|
}, choices=[
|
|
('', 'انتخاب کنید'),
|
|
('domestic', 'شرب و خدمات'),
|
|
('agriculture', 'کشاورزی'),
|
|
('industrial', 'صنعتی')
|
|
]),
|
|
'exploitation_license_number': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'required': True
|
|
}),
|
|
'motor_power': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': '0',
|
|
'step': '1',
|
|
'required': True
|
|
}),
|
|
'pre_calibration_flow_rate': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': '0',
|
|
'step': '0.01',
|
|
'required': True
|
|
}),
|
|
'post_calibration_flow_rate': forms.NumberInput(attrs={
|
|
'class': 'form-control',
|
|
'min': '0',
|
|
'step': '0.01',
|
|
'required': True
|
|
}),
|
|
'water_meter_manufacturer': forms.Select(attrs={
|
|
'class': 'form-select',
|
|
'id': 'id_water_meter_manufacturer',
|
|
'required': True
|
|
}),
|
|
'sim_number': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'required': True
|
|
}),
|
|
'driving_force': forms.TextInput(attrs={
|
|
'class': 'form-control',
|
|
'required': True
|
|
}),
|
|
'is_meter_suspicious': forms.CheckboxInput(attrs={
|
|
'class': 'form-check-input',
|
|
'id': 'id_is_meter_suspicious',
|
|
}),
|
|
'description': forms.Textarea(attrs={
|
|
'class': 'form-control',
|
|
'rows': 3
|
|
})
|
|
}
|
|
|
|
labels = {
|
|
'visited_date': 'تاریخ مراجعه',
|
|
'new_water_meter_serial': 'سریال کنتور جدید',
|
|
'seal_number': 'شماره پلمپ',
|
|
'utm_x': 'UTM X',
|
|
'utm_y': 'UTM Y',
|
|
'meter_type': 'نوع کنتور',
|
|
'meter_size': 'سایز کنتور',
|
|
'discharge_pipe_diameter': 'قطر لوله آبده (اینچ)',
|
|
'usage_type': 'نوع مصرف',
|
|
'exploitation_license_number': 'شماره پروانه بهرهبرداری',
|
|
'motor_power': 'قدرت موتور (کیلووات ساعت)',
|
|
'pre_calibration_flow_rate': 'دبی قبل از کالیبراسیون (لیتر بر ثانیه)',
|
|
'post_calibration_flow_rate': 'دبی بعد از کالیبراسیون (لیتر بر ثانیه)',
|
|
'water_meter_manufacturer': 'شرکت سازنده کنتور',
|
|
'sim_number': 'شماره سیمکارت',
|
|
'driving_force': 'نیرو محرکه چاه',
|
|
'is_meter_suspicious': 'کنتور مشکوک است',
|
|
'description': 'توضیحات'
|
|
}
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
self.user_is_installer = kwargs.pop('user_is_installer', False)
|
|
self.instance_well = kwargs.pop('instance_well', None)
|
|
super().__init__(*args, **kwargs)
|
|
|
|
# Set manufacturer choices
|
|
manufacturers = WaterMeterManufacturer.objects.filter(is_deleted=False)
|
|
manufacturer_choices = [('', 'انتخاب شرکت سازنده')]
|
|
manufacturer_choices.extend([(m.id, m.name) for m in manufacturers])
|
|
self.fields['water_meter_manufacturer'].choices = manufacturer_choices
|
|
|
|
# Pre-fill UTM from well if available and no existing report data
|
|
if self.instance_well and not self.instance.pk:
|
|
if self.instance_well.utm_x:
|
|
self.initial['utm_x'] = self.instance_well.utm_x
|
|
if self.instance_well.utm_y:
|
|
self.initial['utm_y'] = self.instance_well.utm_y
|
|
|
|
# Disable fields for non-installers
|
|
if not self.user_is_installer:
|
|
for field_name, field in self.fields.items():
|
|
if field_name != 'new_manufacturer': # Keep this always disabled via CSS
|
|
field.widget.attrs['readonly'] = True
|
|
if isinstance(field.widget, (forms.Select, forms.CheckboxInput)):
|
|
field.widget.attrs['disabled'] = True
|
|
|
|
def clean(self):
|
|
cleaned_data = super().clean()
|
|
|
|
# Handle new manufacturer creation
|
|
new_manufacturer = cleaned_data.get('new_manufacturer')
|
|
water_meter_manufacturer = cleaned_data.get('water_meter_manufacturer')
|
|
|
|
if new_manufacturer and not water_meter_manufacturer:
|
|
# Create new manufacturer
|
|
manufacturer, created = WaterMeterManufacturer.objects.get_or_create(
|
|
name=new_manufacturer,
|
|
defaults={'is_deleted': False}
|
|
)
|
|
cleaned_data['water_meter_manufacturer'] = manufacturer
|
|
|
|
return cleaned_data
|
|
|
|
def clean_visited_date(self):
|
|
visited_date = self.cleaned_data.get('visited_date')
|
|
if not visited_date:
|
|
raise ValidationError('تاریخ مراجعه الزامی است.')
|
|
return visited_date
|
|
|
|
def clean_exploitation_license_number(self):
|
|
license_number = self.cleaned_data.get('exploitation_license_number')
|
|
if not license_number or not license_number.strip():
|
|
raise ValidationError('شماره پروانه بهرهبرداری الزامی است.')
|
|
return license_number.strip()
|
|
|
|
def validate_photos(self, request_files, existing_photos, deleted_photo_ids):
|
|
"""
|
|
Validate that at least one photo is present (either existing or newly uploaded)
|
|
This method should be called from the view after form.is_valid()
|
|
"""
|
|
# Count existing photos that are not deleted
|
|
kept_existing = 0
|
|
if existing_photos:
|
|
for photo in existing_photos:
|
|
if str(photo.id) not in deleted_photo_ids:
|
|
kept_existing += 1
|
|
|
|
# Count new photos
|
|
new_photos = len(request_files.getlist('photos')) if request_files else 0
|
|
|
|
total_photos = kept_existing + new_photos
|
|
|
|
if total_photos <= 0:
|
|
raise ValidationError('بارگذاری حداقل یک عکس الزامی است.')
|
|
|
|
return True
|