Пример #1
0
  def immediate_upcoming_event(self, time_delta=15, with_seating_chart=False):

    # Code for debugging
    # Turn this boolean to test locally and receive valid event on page load every time
    test_ev_with_chart = False
    if test_ev_with_chart:
      from schedules.models import Event
      ev = Event.objects.filter(chart__isnull=False)[0]
      date = ev.date_for_week(3)
      # calc date from w
      ev.start_datetime = datetime.combine(date, ev.start)
      ev.end_datetime = datetime.combine(date, ev.end)
      return [ev, ]

    # Actual code starts below

    schedules = self.active_schedules
    c_time = datetime.now()
    delay = timedelta(minutes=time_delta)
    start_time = c_time + delay
    end_time = c_time - delay
    c_term = Term.current_term()
    weeks = set([int(c_term.term_week_of_date(c_time.date()))])
    w_tb = OrderedDict()

    for schedule in schedules:
      evs = schedule.events.filter(Q(weekday=c_time.weekday()) | Q(day=c_time.date())).filter(start__lte=start_time, end__gte=end_time)
      if with_seating_chart:
        evs = evs.filter(chart__isnull=False)
      schedule_weeks = set(map(int, schedule.weeks.split(',')))
      w_tb = EventUtils.compute_prioritized_event_table(w_tb, weeks & schedule_weeks, evs, schedule.priority)
    # print w_tb
    return EventUtils.export_event_list_from_table(w_tb)
Пример #2
0
  def events_in_week_list(self, weeks):
    schedules = self.active_schedules
    w_tb = OrderedDict()
    for schedule in schedules:
      evs = schedule.events.all()
      w_tb = EventUtils.compute_prioritized_event_table(w_tb, weeks, evs, schedule.priority)

    # return all the calculated, composite, priority/conflict resolved list of events
    return EventUtils.export_event_list_from_table(w_tb)
Пример #3
0
  def groupevents_in_week_list(self, weeks):
    schedules = self.group_schedule
    w_tb = OrderedDict()
    # create week table
    for schedule in schedules:
      evs = schedule.events.all()
      weeks = [int(x) for x in schedule.weeks.split(',')]
      w_tb = EventUtils.compute_prioritized_event_table(w_tb, weeks, evs, schedule.priority)

    # return all the calculated, composite, priority/conflict resolved list of events
    return EventUtils.export_event_list_from_table(w_tb)
Пример #4
0
    def events_in_date_range(self, start, end, listOfSchedules=[]):
        # check for generic group calendar
        if listOfSchedules:
            schedules = listOfSchedules
        else:
            schedules = self.active_schedules

        # figure out which weeks are in the date range.
        c_term = Term.current_term()
        start_week = c_term.term_week_of_date(start)
        end_week = c_term.term_week_of_date(end)
        w_tb = OrderedDict()
        # for every schedule, filter events to get events in the date range.
        for schedule in schedules:
            # create week table for date range that covers more than one week.
            if end_week - start_week > 0:
                # covers first week.
                evs = schedule.events.filter(
                    Q(weekday__gte=start.weekday())).order_by(
                        'weekday', 'start', 'end')
                weeks = [start_week]
                w_tb = EventUtils.compute_prioritized_event_table(
                    w_tb, weeks, evs, schedule.priority)
                # covers weeks between first and last week.
                evs = schedule.events.all().order_by('weekday', 'start', 'end')
                weeks = range(start_week + 1, end_week)
                w_tb = EventUtils.compute_prioritized_event_table(
                    w_tb, weeks, evs, schedule.priority)
                # covers last week.
                evs = schedule.events.filter(
                    Q(weekday__lte=end.weekday())).order_by(
                        'weekday', 'start', 'end')
                weeks = [end_week]
                w_tb = EventUtils.compute_prioritized_event_table(
                    w_tb, weeks, evs, schedule.priority)
                # create week table for date range that covers only one week.
            else:
                evs = schedule.events.filter(
                    weekday__gte=start.weekday(),
                    weekday__lte=end.weekday()).order_by(
                        'weekday', 'start', 'end')
                weeks = range(start_week, end_week + 1)
                w_tb = EventUtils.compute_prioritized_event_table(
                    w_tb, weeks, evs, schedule.priority)

        # create event list.
        return EventUtils.export_event_list_from_table(w_tb,
                                                       start_datetime=start,
                                                       end_datetime=end)
Пример #5
0
  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)
Пример #6
0
    def get_roll_table_by_type_in_weeks(trainees, monitor, weeks, event_type):
        '''
      Grab all active schedules of trainees and collapse in order of priority.
      This saves us from recalculated shared schedule common among many trainees,
      We only need to collapse them once.

      get_all_schedules_in_weeks_for_trainees():
      --------------------------------------------------------
        Get all the schedules for all trainees (distinct) in order of inc. priorities


      collapse_priority_event_trainee_table():
      --------------------------------------------------------
        Go through all schedules and override conflicting events trainee roster list
      with trainee list that has higher priority

      Returns table {ev: set([trainee1, trainee2])} in order of increasing start/end time of ev


      export_typed_ordered_roll_list():
      --------------------------------------------------------
        Pull out all remaining events after priority-collapsing of type we are taking roll for

        Returns {event: Set([trainee1, trainee2])


      flip_roll_list():
      --------------------------------------------------------
        we flip the table
        Return object {trainee: [Events, ]}
    '''

        t_set = set(trainees)
        schedules = Schedule.get_all_schedules_in_weeks_for_trainees(
            weeks, trainees)
        w_tb = EventUtils.collapse_priority_event_trainee_table(
            weeks, schedules, t_set)
        event_trainee_tb = EventUtils.export_typed_ordered_roll_list(
            w_tb, monitor)
        if monitor == 'AM':
            event_trainee_tb = [
                ev_ts for ev_ts in event_trainee_tb
                if ev_ts[0].type == event_type
            ]

        return EventUtils.flip_roll_list(event_trainee_tb)
Пример #7
0
def validate_rolls_to_schedules(schedules, trainee_set, weeks, rolls):
    roll_ids = []

    current_term = Term.current_term()
    w_tb = EventUtils.collapse_priority_event_trainee_table(
        weeks, schedules, trainee_set)
    potential_rolls = rolls.order_by('date', 'event__start')
    for roll in potential_rolls:
        key = current_term.reverse_date(roll.date)
        evs = w_tb[key]
        if roll.event not in evs or (roll.event in evs
                                     and roll.trainee not in evs[roll.event]):
            roll_ids.append(roll.id)

    invalid_rolls = Roll.objects.filter(id__in=roll_ids)
    return invalid_rolls
Пример #8
0
    def get_context_data(self, **kwargs):
        lJRender = JSONRenderer().render
        ctx = super(RollsView, self).get_context_data(**kwargs)
        user = self.request.user
        trainee = trainee_from_user(user)

        if self.request.method == 'POST':
            selected_week = self.request.POST.get('week')
            event_id = self.request.POST.get('events')
            event = Event.objects.get(id=event_id)
            selected_date = event.date_for_week(int(selected_week))
            event.date = selected_date
            event.start_datetime = datetime.combine(event.date, event.start)
            event.end_datetime = datetime.combine(event.date, event.end)
        else:
            selected_date = date.today()
            selected_week = Event.week_from_date(selected_date)
            # try;
            events = trainee.immediate_upcoming_event(with_seating_chart=True)
            # TODO: - if trainee has no current event load other class that is occuring at the same time
            if len(events) > 0:
                event = events[0]
            else:
                event = None

        selected_week = int(selected_week)

        if event:
            chart = Chart.objects.filter(event=event).first()
            if chart:
                seats = Seat.objects.filter(
                    chart=chart).select_related('trainee')
                partial = Partial.objects.filter(
                    chart=chart).order_by('section_name')
                # Get roll with with for current event and today's date
                roll = Roll.objects.filter(event=event, date=selected_date)
                # TODO - Add group leave slips
                individualslips = IndividualSlip.objects.filter(rolls__in=roll,
                                                                status='A')
                trainees = Trainee.objects.filter(schedules__events=event)
                schedules = Schedule.get_all_schedules_in_weeks_for_trainees([
                    selected_week,
                ], trainees)

                w_tb = EventUtils.collapse_priority_event_trainee_table([
                    selected_week,
                ], schedules, trainees)

                t_set = EventUtils.get_trainees_attending_event_in_week(
                    w_tb, event, selected_week)

                for s in seats:
                    if s.trainee in t_set:
                        s.attending = True
                    else:
                        s.attending = False

                start_datetime = datetime.combine(selected_date, event.start)
                end_datetime = datetime.combine(selected_date, event.end)
                group_slip = GroupSlip.objects.filter(
                    end__gte=start_datetime,
                    start__lte=end_datetime,
                    status='A').prefetch_related('trainees')
                print group_slip, start_datetime, end_datetime
                trainee_groupslip = set()
                for gs in group_slip:
                    trainee_groupslip = trainee_groupslip | set(
                        gs.trainees.all())

                ctx['event'] = event
                ctx['event_bb'] = lJRender(EventWithDateSerializer(event).data)
                ctx['attendance_bb'] = lJRender(
                    RollSerializer(roll, many=True).data)
                ctx['individualslips_bb'] = lJRender(
                    IndividualSlipSerializer(individualslips, many=True).data)
                ctx['trainee_groupslip_bb'] = lJRender(
                    TraineeRollSerializer(trainee_groupslip, many=True).data)
                ctx['trainees_bb'] = lJRender(
                    TraineeRollSerializer(trainees, many=True).data)
                ctx['chart'] = chart
                ctx['chart_bb'] = lJRender(
                    ChartSerializer(chart, many=False).data)
                ctx['seats'] = seats
                ctx['seats_bb'] = lJRender(
                    SeatSerializer(seats, many=True).data)
                ctx['partial'] = partial
                ctx['partial_bb'] = lJRender(
                    PartialSerializer(partial, many=True).data)

        ctx['weekdays'] = WEEKDAYS
        ctx['date'] = selected_date
        ctx['week'] = selected_week
        ctx['day'] = selected_date.weekday()

        # ctx['leaveslips'] = chain(list(IndividualSlip.objects.filter(trainee=self.request.user.trainee).filter(events__term=CURRENT_TERM)), list(GroupSlip.objects.filter(trainee=self.request.user.trainee).filter(start__gte=CURRENT_TERM.start).filter(end__lte=CURRENT_TERM.end)))

        return ctx
Пример #9
0
def attendance_report_trainee(request):

    date_from = datetime.strptime(request.session.get("date_from"),
                                  '%m/%d/%Y').date()
    date_to = datetime.strptime(request.session.get("date_to"),
                                '%m/%d/%Y').date()
    t_id = int(request.GET["traineeId"])
    res = dict()

    trainee = Trainee.objects.get(pk=t_id)
    res["trainee_id"] = t_id
    res["name"] = trainee.lastname + ", " + trainee.firstname
    res["sending_locality"] = trainee.locality.id
    res["term"] = trainee.current_term
    res["team"] = trainee.team.code
    res["ta"] = trainee.TA.full_name
    res["gender"] = trainee.gender

    ct = Term.objects.get(current=True)
    if date_from < ct.start:
        date_from = ct.start
    if date_to > ct.end:
        date_to = ct.end

    rolls = Roll.objects.filter(
        trainee=trainee, date__gte=date_from,
        date__lte=date_to).exclude(status='P').exclude(event__monitor=None)

    start_datetime = datetime.combine(date_from, datetime.min.time())
    end_datetime = datetime.combine(date_to, datetime.max.time())
    group_slips = GroupSlip.objects.filter(status='A',
                                           start__gte=start_datetime,
                                           end__lte=end_datetime,
                                           trainees=trainee).values(
                                               'start', 'end')

    week_from = ct.reverse_date(date_from)[0]
    week_to = ct.reverse_date(date_to)[0]
    weeks = range(week_from, week_to)
    w_tb = EventUtils.collapse_priority_event_trainee_table(
        weeks, trainee.active_schedules, [trainee])
    count = Counter()
    for kv in w_tb:
        for ev, t in w_tb[kv].items():
            if ev in count:
                count[ev] += 1
            else:
                count[ev] = 1

    # CALCULATE %TARDY
    total_possible_rolls_count = max(
        1, sum(count[ev] for ev in count if ev.monitor is not None))
    tardy_rolls = rolls.exclude(
        status='A').filter(~(Q(leaveslips__does_not_count=True)
                             & Q(leaveslips__status='A')))
    tardy_rolls = rolls_excused_by_groupslips(
        tardy_rolls, group_slips.filter(does_not_count=True))

    res["tardy_percentage"] = str(
        round(tardy_rolls.count() / float(total_possible_rolls_count) * 100,
              2)) + "%"

    # CALCULATE %CLASSES MISSED
    possible_class_rolls_count = max(
        1,
        sum(count[ev] for ev in count
            if ev.monitor == 'AM' and ev.type == 'C'))
    missed_classes = rolls.filter(event__monitor='AM', event__type='C')

    # currently counts rolls excused by individual and group slips
    # comment this part out to not count those rolls
    # exclude absent rolls excused by individual slips
    # missed_classes = missed_classes.exclude(leaveslips__status='A')

    missed_classes = missed_classes.filter(~(Q(leaveslips__does_not_count=True)
                                             & Q(leaveslips__status='A')))

    # exclude absent rolls excused by group slips
    missed_classes = rolls_excused_by_groupslips(
        missed_classes, group_slips.filter(does_not_count=True))

    res["classes_missed_percentage"] = str(
        round(missed_classes.count() / float(possible_class_rolls_count) * 100,
              2)) + "%"

    # CALCULATE %SICKNESS
    rolls_covered_by_sickness = Roll.objects.filter(
        trainee=trainee,
        leaveslips__status='A',
        leaveslips__type='SICK',
        date__gte=date_from,
        date__lte=date_to).distinct()

    res["sickness_percentage"] = str(
        round(
            rolls_covered_by_sickness.count() /
            float(total_possible_rolls_count) * 100, 2)) + "%"

    # CALCULATE UNEXCUSED ABSENCES
    unexcused_absences = rolls.filter(status='A')
    unexcused_absences = unexcused_absences.exclude(leaveslips__status='A')
    unexcused_absences = rolls_excused_by_groupslips(unexcused_absences,
                                                     group_slips)
    res["unexcused_absences_percentage"] = str(
        round(
            unexcused_absences.count() / float(total_possible_rolls_count) *
            100, 2)) + "%"

    stash.append_records(res)
    return JsonResponse(res)
Пример #10
0
    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