import datetime import logging from django import forms from django.forms import ModelForm, Form from django.utils.dates import MONTHS from web.models import Appointment, AppointmentType, AppointmentTypeLink, \ Availability, ContactAttempt, FlyingTeam, Holiday, Item, \ StudySubject, Room, Worker, Visit, VoucherType, VoucherTypePrice from web.models.constants import SUBJECT_TYPE_CHOICES """ Possible redundancy, but if need arises, contents of forms can be easily customized """ DATE_FORMAT_TIME = "%H:%M" CURRENT_YEAR = datetime.datetime.now().year YEAR_CHOICES = tuple(range(CURRENT_YEAR, CURRENT_YEAR - 120, -1)) FUTURE_YEAR_CHOICES = tuple(range(CURRENT_YEAR, CURRENT_YEAR + 5, 1)) DATEPICKER_DATE_ATTRS = { 'class': 'datepicker', 'data-date-format': 'yyyy-mm-dd', 'data-date-orientation': 'bottom' } DATETIMEPICKER_DATE_ATTRS = { 'class': 'datetimepicker', 'data-date-format': 'Y-MM-DD HH:mm', } TIMEPICKER_DATE_ATTRS = { 'class': 'datetimepicker', 'data-date-format': 'HH:mm', 'data-date-stepping': 15, } START_YEAR_STATISTICS = 2015 APPOINTMENT_TYPES_FIELD_POSITION = 1 logger = logging.getLogger(__name__) def get_worker_from_args(kwargs): user = kwargs.pop('user', None) if user is None: raise TypeError("User not defined") result = Worker.get_by_user(user) if result is None: raise TypeError("Worker not defined for: " + user.username) return result class VisitDetailForm(ModelForm): datetime_begin = forms.DateField(label="Visit begins on", widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d") ) datetime_end = forms.DateField(label="Visit ends on", widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d") ) post_mail_sent = forms.RadioSelect() appointment_types = forms.ModelMultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, queryset=AppointmentType.objects.all()) def __init__(self, *args, **kwargs): super(VisitDetailForm, self).__init__(*args, **kwargs) instance = getattr(self, 'instance', None) if instance.is_finished: #set form as readonly for key in self.fields.keys(): self.fields[key].widget.attrs['readonly'] = True class Meta: model = Visit exclude = ['is_finished', 'visit_number'] class VisitAddForm(ModelForm): subject = forms.ModelChoiceField( queryset=StudySubject.objects.order_by('subject__last_name', 'subject__first_name')) datetime_begin = forms.DateField(label="Visit begins on", widget=forms.TextInput(attrs=DATEPICKER_DATE_ATTRS) ) datetime_end = forms.DateField(label="Visit ends on", widget=forms.TextInput(attrs=DATEPICKER_DATE_ATTRS) ) appointment_types = forms.ModelMultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, queryset=AppointmentType.objects.all()) class Meta: model = Visit exclude = ['is_finished', 'visit_number'] def clean(self): super(VisitAddForm, self).clean() if 'datetime_begin' not in self.cleaned_data or 'datetime_end' not in self.cleaned_data: return if self.cleaned_data['datetime_begin'] >= self.cleaned_data['datetime_end']: self.add_error('datetime_begin', "Start date must be before end date") self.add_error('datetime_end', "End date must be after start date") class KitRequestForm(Form): start_date = forms.DateField(label="From date", widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d"), required=False ) end_date = forms.DateField(label="End date", widget=forms.DateInput(DATEPICKER_DATE_ATTRS, "%Y-%m-%d"), required=False ) class StatisticsForm(Form): def __init__(self, *args, **kwargs): super(StatisticsForm, self).__init__(*args) visit_choices = kwargs['visit_choices'] month = kwargs['month'] year = kwargs['year'] now = datetime.datetime.now() year_now = now.year number_of_years_for_statistics = year_now - START_YEAR_STATISTICS + 2 year_choices = [(START_YEAR_STATISTICS + i, START_YEAR_STATISTICS + i) for i in range(0, number_of_years_for_statistics + 1)] self.fields['month'] = forms.ChoiceField(choices=MONTHS.items(), initial=month) self.fields['year'] = forms.ChoiceField(choices=year_choices, initial=year) choices = [(-1, "all")] choices.extend(SUBJECT_TYPE_CHOICES.items()) self.fields['subject_type'] = forms.ChoiceField(choices=choices, initial="-1") self.fields['visit'] = forms.ChoiceField(choices=visit_choices, initial="-1") class AvailabilityAddForm(ModelForm): def __init__(self, *args, **kwargs): super(AvailabilityAddForm, self).__init__(*args, **kwargs) self.fields['person'].widget.attrs['readonly'] = True available_from = forms.TimeField(label="Available from", widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), initial="8:00", ) available_till = forms.TimeField(label="Available until", widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), initial="17:00", ) class Meta: model = Availability fields = '__all__' def clean(self): worker = Worker.objects.get(id=self.cleaned_data["person"].id) availabilities = worker.availability_set.all() for availability in availabilities: validate_availability_conflict(self, self.cleaned_data, availability) class AvailabilityEditForm(ModelForm): available_from = forms.TimeField(label="Available from", widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), ) available_till = forms.TimeField(label="Available until", widget=forms.TimeInput(TIMEPICKER_DATE_ATTRS), ) class Meta: model = Availability fields = '__all__' def __init__(self, *args, **kwargs): super(ModelForm, self).__init__(*args, **kwargs) instance = getattr(self, 'instance', None) if instance is not None: self.availability_id = instance.id self.fields['person'].disabled = True def clean(self): worker = Worker.objects.get(id=self.cleaned_data["person"].id) availabilities = worker.availability_set.all() for availability in availabilities: if availability.id != self.availability_id: validate_availability_conflict(self, self.cleaned_data, availability) def validate_availability_conflict(self, cleaned_data, availability): start_hour = self.cleaned_data.get("available_from", None) end_hour = self.cleaned_data.get("available_till", None) if availability.day_number == self.cleaned_data.get("day_number", None) and \ ((start_hour <= availability.available_from < end_hour) or (start_hour < availability.available_till <= end_hour) or (availability.available_from <= start_hour < availability.available_till) or (availability.available_from < end_hour <= availability.available_till)): error = "User has defined availability for this day that overlaps: " + availability.available_from.strftime( DATE_FORMAT_TIME) + ", " + availability.available_till.strftime(DATE_FORMAT_TIME) self.add_error('day_number', error) self.add_error('available_from', error) self.add_error('available_till', error) class ItemForm(ModelForm): class Meta: model = Item fields = "__all__" class FlyingTeamAddForm(ModelForm): class Meta: model = FlyingTeam fields = "__all__" class FlyingTeamEditForm(ModelForm): class Meta: model = FlyingTeam fields = "__all__" class HolidayAddForm(ModelForm): def __init__(self, *args, **kwargs): super(HolidayAddForm, self).__init__(*args, **kwargs) self.fields['person'].widget.attrs['readonly'] = True datetime_start = forms.DateTimeField(widget=forms.DateTimeInput(DATETIMEPICKER_DATE_ATTRS), initial=datetime.datetime.now().replace(hour=8, minute=0), ) datetime_end = forms.DateTimeField(widget=forms.DateTimeInput(DATETIMEPICKER_DATE_ATTRS), initial=datetime.datetime.now().replace(hour=17, minute=0), ) class Meta: model = Holiday fields = '__all__' def clean(self): worker = Worker.objects.get(id=self.cleaned_data["person"].id) availabilities = worker.availability_set.all() for availability in availabilities: validate_availability_conflict(self, self.cleaned_data, availability) class RoomForm(ModelForm): class Meta: model = Room fields = '__all__'