import logging from collections import OrderedDict from django import forms from django.forms import ModelForm from web.models.worker_study_role import WORKER_STAFF from web.forms.forms import DATETIMEPICKER_DATE_ATTRS, APPOINTMENT_TYPES_FIELD_POSITION from web.models import Appointment, Worker, AppointmentTypeLink, AppointmentType, Provenance from web.views.notifications import get_filter_locations from django.db.models.query import QuerySet logger = logging.getLogger(__name__) class AppointmentForm(ModelForm): datetime_when = forms.DateTimeField(label='Appointment on', widget=forms.DateTimeInput(DATETIMEPICKER_DATE_ATTRS) ) def __init__(self, *args, **kwargs): super(AppointmentForm, self).__init__(*args, **kwargs) self.fields['worker_assigned'].queryset = Worker.get_workers_by_worker_type(WORKER_STAFF).filter( locations__in=get_filter_locations(self.user)).distinct().order_by('first_name', 'last_name') def save_changes(self): for change in self.changes: if change.modified_table_id is None: change.modified_table_id = self.instance.id change.save() def register_changes(self): self.changes = [] for field in self.changed_data: new_value = self.cleaned_data[field] if isinstance(new_value, QuerySet): new_human_values = '; '.join([str(element) for element in new_value]) new_value = ','.join([str(element.id) for element in new_value]) #overwrite variable #old value if self.instance.id: #update instance previous_value = getattr(self.instance, field).all() old_human_values = '; '.join([str(element) for element in previous_value]) previous_value = ','.join([str(element.id) for element in previous_value]) #overwrite variable else: #new instance old_human_values = '' previous_value = '' #description description = '{} changed from "{}" to "{}"'.format(field, old_human_values, new_human_values) else: if self.instance.id: #update instance previous_value = str(getattr(self.instance, field)) else: previous_value = '' new_value = str(self.cleaned_data[field]) description = '{} changed from "{}" to "{}"'.format(field, previous_value, new_value) p = Provenance(modified_table = Appointment._meta.db_table, modified_table_id = self.instance.id, modification_author=self.user, previous_value = previous_value, new_value = new_value, modification_description = description, modified_field = field, ) self.changes.append(p) class AppointmentDetailForm(AppointmentForm): class Meta: model = Appointment fields = '__all__' class AppointmentEditForm(AppointmentForm): class Meta: model = Appointment fields = '__all__' exclude = ['appointment_types'] def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) if user is None: raise TypeError("User not defined") self.user = Worker.get_by_user(user) if self.user is None: raise TypeError("Worker not defined for: " + user.username) super(AppointmentEditForm, self).__init__(*args, **kwargs) if 'instance' in kwargs: initial_appointment_types = AppointmentTypeLink.objects.filter(appointment=kwargs['instance']).values_list( 'appointment_type', flat=True) else: initial_appointment_types = [] fields = OrderedDict() for i, tuple in enumerate(self.fields.items()): key, value = tuple fields[key] = value if i == APPOINTMENT_TYPES_FIELD_POSITION: fields['appointment_types'] = forms.ModelMultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, queryset=AppointmentType.objects.all(), initial=initial_appointment_types) self.fields = fields self.fields['location'].queryset = get_filter_locations(self.user) def clean_location(self): location = self.cleaned_data['location'] if self.user.locations.filter(id=location.id).count() == 0: self.add_error('location', "You cannot create appointment for this location") else: return location def clean(self): self.register_changes() #right before instance is changed def save(self, commit=True): appointment = super(AppointmentEditForm, self).save(commit) # if appointment date change, remove appointment_type links if 'datetime_when' in self.changed_data: AppointmentTypeLink.objects.filter(appointment=appointment).delete() appointment_type_links = [] else: appointment_type_links = AppointmentTypeLink.objects.filter(appointment=appointment).all() appointment_types_from_links = [] appointment_types = self.cleaned_data['appointment_types'] for appointment_type_link in appointment_type_links: if appointment_type_link.appointment_type not in appointment_types: # we delete appointment links for appointments types that have been removed appointment_type_link.delete() else: appointment_types_from_links.append(appointment_type_link.appointment_type) for appointment_type in appointment_types: if appointment_type not in appointment_types_from_links: # we create new appointment links for appointments types that have been added appointment_type_link = AppointmentTypeLink(appointment=appointment, appointment_type=appointment_type) appointment_type_link.save() self.save_changes() return appointment class AppointmentAddForm(AppointmentForm): class Meta: model = Appointment exclude = ['status', 'appointment_types'] def __init__(self, *args, **kwargs): user = kwargs.pop('user', None) if user is None: raise TypeError("User not defined") self.user = Worker.get_by_user(user) if self.user is None: raise TypeError("Worker not defined for: " + user.username) super(AppointmentAddForm, self).__init__(*args, **kwargs) fields = OrderedDict() for i, tuple in enumerate(self.fields.items()): key, value = tuple fields[key] = value if i == APPOINTMENT_TYPES_FIELD_POSITION: fields['appointment_types'] = forms.ModelMultipleChoiceField(required=False, widget=forms.CheckboxSelectMultiple, queryset=AppointmentType.objects.all(), ) fields['worker_assigned'].widget.attrs = {'class': 'search_worker_availability'} fields['datetime_when'].widget.attrs = {'class': 'start_date', 'placeholder': 'yyyy-mm-dd HH:MM', 'pattern': '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}'} fields['length'].widget.attrs = {'class': 'appointment_duration'} self.fields = fields self.fields['location'].queryset = get_filter_locations(self.user) def clean(self): self.register_changes() #right before instance is changed def clean_location(self): location = self.cleaned_data['location'] if self.user.locations.filter(id=location.id).count() == 0: self.add_error('location', "You cannot create appointment for this location") else: return location def save(self, commit=True): appointment = super(AppointmentAddForm, self).save(commit) appointment_types = self.cleaned_data['appointment_types'] for appointment_type in appointment_types: appointment_type_link = AppointmentTypeLink(appointment=appointment, appointment_type=appointment_type) appointment_type_link.save() self.save_changes() return appointment