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', 'meter_model', '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' }), 'meter_model': forms.Select(attrs={ 'class': 'form-select' }, choices=[ ('', 'انتخاب کنید'), ('direct', 'مستقیم'), ('indirect', 'غیرمستقیم') ]), 'discharge_pipe_diameter': forms.NumberInput(attrs={ 'class': 'form-control', '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', 'required': True }), 'pre_calibration_flow_rate': forms.NumberInput(attrs={ 'class': 'form-control', 'min': '0', 'step': '0.0001', 'required': True }), 'post_calibration_flow_rate': forms.NumberInput(attrs={ 'class': 'form-control', 'min': '0', 'step': '0.0001', '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