def clean(self):
        error_messages = []
        # try:
        cleaned_data = super(RNForm, self).clean()
        Team = cleaned_data.get("Team")
        StartTime = cleaned_data.get("StartTime")
        LunchTime = cleaned_data.get("LunchTime")
        LunchDuration = cleaned_data.get("LunchDuration")
        EndTime = cleaned_data.get("EndTime")

        OpenTime = datetime.time(datetime.strptime(UserSettings.get("OpenTime"),"%H:%M"))
        CloseTime = datetime.time(datetime.strptime(UserSettings.get("CloseTime"),"%H:%M"))

        # does not conform to DRY principle?
        if not Team or not StartTime or not EndTime:
            raise forms.ValidationError('Please fill out all of the fields')
        if StartTime >= EndTime:
            error_messages.append('RNs cannot start after EndTime')
        if StartTime < OpenTime:
            error_messages.append('A RN can not start before the company opens at ' + OpenTime.strftime("%I:%M"))
        if EndTime > CloseTime:
            error_messages.append('A RN must leave before the company closes at ' + CloseTime.strftime("%I:%M"))
        if not LunchTime or (LunchTime and (LunchTime < StartTime or LunchTime > EndTime)):
            error_messages.append('RNs need a valid lunch start time')
        if len(error_messages):
            raise forms.ValidationError(' & '.join(error_messages))
        return self.cleaned_data
def add_to_schedule_group(request):
    r = request.GET
    group_name = r['ScheduleGroupName']
    try:  # check if the name has already been used
        group_object = NurseScheduleGroups.objects.get(Name=group_name, UserCreated=True)
    except (KeyError, NurseScheduleGroups.DoesNotExist):
        # if the name has already been used add the nurse to the group
        group_object = NurseScheduleGroups(Name=group_name, UserCreated=True, Chairs=UserSettings.get("MaxChairs"))
        group_object.save()
    rn = NurseSchedule(
        Team=r['Team'],
        ScheduleGroupName=group_object,
        StartTime=r['StartTime'],
        LunchTime=r['LunchTime'],
        LunchDuration=r['LunchDuration'],
        EndTime=r['EndTime']
    )
    rn.save()
    return HttpResponse('The rn schedule ' + group_name + 'has been saved', content_type="application/json")
def new_schedule(request):
    chairs = UserSettings.get("MaxChairs")
    if request.method == 'POST':  # if this is a POST request we need to process the form data
        rn_form = RNFormSet(request.POST, prefix='RN')
        app_form = AppointmentFormSet(request.POST, prefix='APP')
        reserved_form = ReservedFormSet(request.POST, prefix='RESERVED')
        prioritize_longest = len(request.POST.getlist('PrioritizeLongest')) > 0
        if rn_form.is_valid() & app_form.is_valid() & reserved_form.is_valid():
            # -----Build nurse objects---- #
            nurses = []
            for form in rn_form:
                cd = form.cleaned_data
                nurses.append(NurseSchedule(
                    NurseID=0,
                    Team=cd.get('Team'),
                    StartTime=cd.get('StartTime'),
                    LunchTime=cd.get('LunchTime'),
                    LunchDuration=cd.get('LunchDuration'),
                    EndTime=cd.get('EndTime')
                ))
            nurses = sorted(nurses, key=lambda x: x.Team)  # sort by team for easier viewing
            for i in range(1, len(nurses)+1):
                nurses[i-1].NurseID = i
            # -----Build list of needed time slots----- #
            needed_appointments = []
            for form in app_form:
                cd = form.cleaned_data
                needed_appointments.append([int(cd.get('TimePeriod')), int(cd.get('Amount'))])
            needed_appointments = sorted(needed_appointments, key=itemgetter(0), reverse=True)
            # -----Build list of pre-reserved time slots----- #
            reserved_appointments = []
            for form in reserved_form:
                cd = form.cleaned_data
                app = Appointment(
                    StartTime=cd.get('StartTime'),
                    EndTime=cd.get('EndTime'),
                    NurseScheduleID=cd.get('RNNumber'),
                    ChairID=int(cd.get('ChairNumber'))
                )
                setattr(app, 'reserved', True)
                reserved_appointments.append(app)
            # -----Run Algorithm and build the context----- #
            cleaned_input = clean_input(nurses, needed_appointments, reserved_appointments)  # clean the input
            all_appointments = run_algorithm(cleaned_input[0], cleaned_input[2])
            scheduled_appointments = all_appointments[0] + cleaned_input[1]
            scheduled_appointments = sorted(scheduled_appointments, key=attrgetter('NurseScheduleID', 'ChairID', 'StartTime'))
            unscheduled_appointments = all_appointments[1]
            maxtime = max(nurses, key=attrgetter('EndTime')).EndTime
            if maxtime.minute == 0:
                maxhour = maxtime.hour - 1
            else:
                maxhour = maxtime.hour
            mintime = min(nurses, key=attrgetter('StartTime')).StartTime
            context = {'RNSet': nurses, 'RNSize': chairs+1, 'Appointments': scheduled_appointments, 'Chairs': range(0, chairs),
                       'UnschAppts': unscheduled_appointments,
                       'Drugs': ChemotherapyDrug.objects.all(),
                       'DayDuration': getHourRange(mintime, maxtime), 'closeTime': maxhour}
            # -----save to the session in case user saves calendar later----- #
            request.session['nurseSchedules'] = serializers.serialize('json', nurses)
            request.session['appointments'] = serializers.serialize('json', scheduled_appointments)
            return render(request, 'calendar.html', context)
        # end if form is valid
        context = {'RNFormSet': rn_form, 'Chairs': range(0, chairs), 'AppointmentFormSet': app_form, 'ReservedFormSet': reserved_form}
        return render(request, 'new_schedule.html', context)
    else:  # not post
        rn_form = RNFormSet(prefix='RN')
        app_form = AppointmentFormSet(prefix='APP')
        appointment = AppointmentForm()
        appt_minutes = []
        for x,y in appointment.TIMESLOTS:
            appt_minutes.append(x)
        reserved_form = ReservedFormSet(prefix='RESERVED')
        context = {'RNFormSet': rn_form, 'Chairs': range(0, chairs), 'AppointmentFormSet': app_form, 'ReservedFormSet': reserved_form, 'appt_ts': appt_minutes}
        return render(request, 'new_schedule.html', context)
def save_schedule(request):
    # todo: check if the session is still valid
    save_name = request.GET['SaveName']
    # Save the nurse schedules
    nurse_group = NurseScheduleGroups(Name=generate_key(20), UserCreated=False, Chairs=UserSettings.get("MaxChairs"))
    nurse_group.save()
    for wrapper in serializers.deserialize('json', request.session.get('nurseSchedules')):
        wrapper.object.ScheduleGroupName = nurse_group
        wrapper.object.save()
    # Save the schedule object that links nurses and appointments
    schedule = SavedSchedule(Name=save_name, NurseSchedule=nurse_group)
    schedule.save()
    # Save the appointments
    for wrapper in serializers.deserialize('json', request.session.get('appointments')):
        wrapper.object.SavedSchedule = schedule
        wrapper.object.save()
    return HttpResponse('The schedule ' + save_name + ' has been saved', content_type="application/json")