def form_valid(self, form): new_schedule = form.instance cur_schedule = Schedule.objects.get(id=new_schedule.id) new_set = new_schedule.trainees.all() current_set = cur_schedule.trainees.all() # If the trainee sets are identical, minor schedule update to_add = new_set.exclude(pk__in=current_set) to_delete = current_set.exclude(pk__in=new_set) if not to_add and not to_delete: return super(ScheduleAdminUpdate, self).form_valid(form) for t in to_delete: # trainee cannot be moved off of a schedule if there are rolls for events on that schedule t_events = t.rolls.order_by('event').distinct('event').values_list('event__id', flat=True) if cur_schedule.events.filter(id__in=t_events).exists(): form._errors[NON_FIELD_ERRORS] = ErrorList([u'Trainee(s) cannot be removed from schedule. Split the schedule.']) return super(ScheduleAdminUpdate, self).form_invalid(form) for t in to_add: # trainee cannot be moved onto a schedule if there are rolls for events on a schedule that it will overlap sch_event_set = cur_schedule.events.values('event__id', 'event__start', 'event__end') tr_event_set = t.rolls.order_by('event').distinct('event').values('event__id', 'event__start', 'event__end') for i in tr_event_set: for j in sch_event_set: if EventUtils.time_overlap(i['event__start'], i['event__end'], j['event__start'], j['event__end']): form._errors[NON_FIELD_ERRORS] = ErrorList([u'Trainee(s) cannot be added to schedule. Split the schedule.']) return super(ScheduleAdminUpdate, self).form_invalid(form) return super(ScheduleAdminUpdate, self).form_valid(form)
def get_attendance_record(self, period=None): from leaveslips.models import GroupSlip c_term = Term.current_term() rolls = self.rolls.exclude(status='P').filter( date__gte=c_term.start, date__lte=c_term.end).order_by( 'event', 'date').distinct('event', 'date').prefetch_related('event') ind_slips = self.individualslips.filter(status__in=['A', 'S']) att_record = [] # list of non 'present' events excused_timeframes = [] # list of groupslip time ranges excused_rolls = [] # prevents duplicate rolls def attendance_record(att, start, end, event): return { 'attendance': att, 'start': start, 'end': end, 'event': event, } def reformat(slip): s = str( datetime.combine(slip['rolls__date'], slip['rolls__event__start'])).replace( ' ', 'T') e = str( datetime.combine(slip['rolls__date'], slip['rolls__event__end'])).replace(' ', 'T') return (s, e) group_slips = GroupSlip.objects.filter(trainees=self, status__in=['A', 'S']) rolls = rolls.order_by('event__id', 'date').distinct( 'event__id', 'date') # may not need to order if period is not None: # works without period, but makes calculate_summary really slow p = Period(c_term) start_date = p.start(period) end_date = p.end(period) startdt = datetime.combine(start_date, datetime.min.time()) enddt = datetime.combine(end_date, datetime.max.time()) rolls = rolls.filter( date__gte=start_date, date__lte=end_date) # rolls for current period ind_slips = ind_slips.filter( rolls__in=[d['id'] for d in rolls.values('id')]) group_slips = group_slips.filter(start__lte=enddt, end__gte=startdt) rolls = rolls.values('event__id', 'event__start', 'event__end', 'event__name', 'status', 'date') ind_slips = ind_slips.values('rolls__event__id', 'rolls__event__start', 'rolls__event__end', 'rolls__date', 'rolls__event__name', 'id') excused_timeframes = group_slips.values('start', 'end') # first, individual slips for slip in ind_slips: if slip['rolls__event__id'] is None: continue start, end = reformat(slip) att_record.append( attendance_record('E', start, end, slip['rolls__event__id'])) excused_rolls.append( (slip['rolls__event__id'], slip['rolls__date'])) for roll in rolls: excused = False for excused_roll in excused_rolls: if roll['event__id'] == excused_roll[0] and roll[ 'date'] == excused_roll[ 1]: # Check if roll is excused using the roll's event and the roll's date excused = True break if excused is False: if roll['status'] == 'A': # absent rolls att_record.append( attendance_record( 'A', str(roll['date']) + 'T' + str(roll['event__start']), str(roll['date']) + 'T' + str(roll['event__end']), roll['event__id'])) else: # tardy rolls att_record.append( attendance_record( 'T', str(roll['date']) + 'T' + str(roll['event__start']), str(roll['date']) + 'T' + str(roll['event__end']), roll['event__id'])) # now, group slips for record in att_record: if record['event'] is None: continue if record['attendance'] != 'E': start_dt = parser.parse(record['start']) end_dt = parser.parse(record['end']) for tf in excused_timeframes: if EventUtils.time_overlap(start_dt, end_dt, tf['start'], tf['end']): record['attendance'] = 'E' return att_record