Ejemplo n.º 1
0
    def has_good_lunch(self, lunch_duration, hours_wo_lunch):

        lunch_stops = [x for x in self.stops if x.stop_name in ("LUNCH", "Lunch")]

        if len(lunch_stops) > 1:
            print("Multiple lunches found!!")
            return False

        if len(lunch_stops) < 1:
            return False

        lunch_stop = lunch_stops[0]

        if lunch_stop.layover() < lunch_duration:
            # print("lunch found, but too short")
            return False

        start_time = self.stops[0].arrive_time
        stop_time = self.stops[-1].depart_time

        if dur(start_time, lunch_stop.arrive_time) > hours_wo_lunch * 60:
            # print("lunch found, is too late")
            return False

        if dur(lunch_stop.depart_time, stop_time) > hours_wo_lunch * 60:
            # print("lunch found, is too early")
            return False

        return True
Ejemplo n.º 2
0
    def duration_postalized(self):

        # note this method adds individual travel times and layovers rather than comparing the first
        # and last times of the schedule to account for schedules over 24 hours

        duration = 0
        for x, stop in enumerate(self.stops_postalized[:-1]):
            next_stop = self.stops[x + 1]
            duration += stop.layover()
            duration += dur(stop.depart_time, next_stop.arrive_time)

        duration += self.stops[-1].layover()

        return duration
Ejemplo n.º 3
0
    def layover(self):

        return dur(self.arrive_time, self.depart_time)
Ejemplo n.º 4
0
    def add_a_lunch(self, input_passer):

        hours_wo_lunch = input_passer.hours_wo_lunch
        lunch_duration = input_passer.lunch_duration
        allow_extension = input_passer.allow_extension
        allow_non_postal = input_passer.allow_non_postal
        lunch_travel_time = input_passer.lunch_travel_time
        lunch_buffer_time = input_passer.lunch_buffer_time
        total_buffer = lunch_travel_time + lunch_buffer_time

        duration = self.duration_current()
        if duration < hours_wo_lunch * 60:
            return True

        if self.has_good_lunch(lunch_duration, hours_wo_lunch):
            return True

        existing_lunch = [x for x in self.stops if x.stop_name in ("LUNCH", "Lunch")]
        if len(existing_lunch) > 0:
            # print("already tried best we could")
            return False

        start_time = self.stops[0].arrive_time
        stop_time = self.stops[-1].depart_time

        max_td = timedelta(hours=hours_wo_lunch)
        one_day = timedelta(hours=24)

        start_dt = time_to_datetime(start_time)
        stop_dt = time_to_datetime(stop_time)
        if stop_dt < start_dt:
            stop_dt += one_day

        earliest_possible_lunch_dt = stop_dt - max_td
        latest_possible_lunch_dt = start_dt + max_td

        if earliest_possible_lunch_dt > latest_possible_lunch_dt:
            print("Schedule " + self.schedule_name + " is too long for one lunch.")
            return False

        earliest_possible_time = earliest_possible_lunch_dt.time()
        latest_possible_time = latest_possible_lunch_dt.time()

        earliest_possible_minute = max(26, dur(start_time, earliest_possible_time)+total_buffer)
        latest_possible_minute = dur(start_time, latest_possible_time)-total_buffer

        first_start_time = self.stops[0].arrive_time

        postal_stops = []
        extend_stops = []
        non_postal_stops = []
        extend_non_postal_stops = []
        potential_stops = 0

        for x, stop in enumerate(self.stops):
            start_minute = dur(first_start_time, stop.arrive_time)
            stop_minute = dur(first_start_time, stop.depart_time)
            layover_minutes = stop_minute - start_minute

            if stop_minute > earliest_possible_minute:
                if start_minute < latest_possible_minute:
                    if stop.post_office_location:
                        if layover_minutes >= (lunch_duration + 2*(lunch_travel_time + lunch_buffer_time)):
                            postal_stops.append(x)
                            potential_stops += 1
                        elif allow_extension:
                            extend_stops.append(x)
                            potential_stops += 1
                    elif allow_non_postal:
                        if layover_minutes >= (lunch_duration + 2*(lunch_travel_time + lunch_buffer_time)):
                            non_postal_stops.append(x)
                            potential_stops += 1
                        elif allow_extension:
                            extend_non_postal_stops.append(x)
                            potential_stops += 1

        if potential_stops == 0:
            # print("No eligible lunch stops found")
            return False
        # else:
            # print("Found " + str(potential_stops) + " eligible stops for lunch")

        if len(postal_stops) > 0:

            index = postal_stops[0]
            stop = self.stops[index]
            must_start_by = latest_possible_minute - dur(start_time, stop.arrive_time) + total_buffer
            # cant_finish_before = earliest_possible_minute - dur(start_time, stop.arrive_time)
            self.insert_lunch(index, lunch_duration, must_start_by, lunch_travel_time, lunch_buffer_time)

        elif len(non_postal_stops) > 0:
            index = non_postal_stops[0]
            stop = self.stops[index]
            must_start_by = latest_possible_minute - dur(start_time, stop.arrive_time) + total_buffer
            # cant_finish_before = earliest_possible_minute - dur(start_time, stop.arrive_time)
            self.insert_lunch(index, lunch_duration, must_start_by, lunch_travel_time, lunch_buffer_time)

        elif len(extend_stops) > 0:
            index = extend_stops[0]
            for x in extend_stops:
                if self.stops[x].layover() > self.stops[index].layover():
                    index = x

            orig_layover = self.stops[index].layover()
            required_layover = lunch_duration + 2*(lunch_travel_time + lunch_buffer_time)
            pushback_minutes = required_layover - orig_layover

            self.stops[index].change_depart_time(pushback_minutes)

            stop = self.stops[index]
            must_start_by = latest_possible_minute - dur(start_time, stop.arrive_time) + total_buffer
            # cant_finish_before = earliest_possible_minute - dur(start_time, stop.arrive_time)

            self.insert_lunch(index, lunch_duration, must_start_by, lunch_travel_time, lunch_buffer_time)

            for stop in self.stops[index+3:]:
                stop.shift_stop(pushback_minutes)
            for stop in self.stops:
                stop.shift_stop(-round(pushback_minutes/2, 0))

        elif len(extend_non_postal_stops) > 0:
            index = extend_non_postal_stops[0]

            for x in extend_non_postal_stops:
                if self.stops[x].layover() > self.stops[index].layover():
                    index = x

            orig_layover = self.stops[index].layover()
            required_layover = lunch_duration + 2*(lunch_travel_time + lunch_buffer_time)
            pushback_minutes = required_layover - orig_layover

            self.stops[index].change_depart_time(pushback_minutes)

            stop = self.stops[index]
            must_start_by = latest_possible_minute - dur(start_time, stop.arrive_time) + total_buffer
            # cant_finish_before = earliest_possible_minute - dur(start_time, stop.arrive_time)

            self.insert_lunch(index, lunch_duration, must_start_by, lunch_travel_time, lunch_buffer_time)

            for stop in self.stops[index+3:]:
                stop.shift_stop(pushback_minutes)
            for stop in self.stops:
                stop.shift_stop(-round(pushback_minutes/2, 0))

        else:
            print("wtf? eligible lunch stops both found and not found??")

        return True
Ejemplo n.º 5
0
    def postal_compliance_check(self, input_passer):

        pvs_time = input_passer.pvs_time
        pdc_time = input_passer.pdc_time
        pvs_to_pdc = input_passer.pvs_to_pdc
        layover_time = pvs_time + pdc_time + pvs_to_pdc

        pvs_name = self.pvs_name
        pdc_name = self.pdc_name
        max_working_time = input_passer.max_duration
        lunch_duration = input_passer.lunch_duration
        hours_wo_lunch = input_passer.hours_wo_lunch

        # check all layovers longer than one minute
        for stop in self.stops:
            if not stop.is_good_stop():
                return False

        # check all travel times at least one minute
        for x, stop in enumerate(self.stops[:-1]):
            next_stop = self.stops[x+1]
            travel_time = dur(stop.depart_time, next_stop.arrive_time)
            if travel_time < 1:
                return False

        # check the PVS and P&DC start situation
        start_check = False
        if self.same_name:
            if self.stops[0].stop_name == pvs_name:
                if self.stops[0].layover() == layover_time:
                    start_check = True
        else:
            if self.stops[0].stop_name == pvs_name:
                if self.stops[1].stop_name == pdc_name:
                    if self.stops[0].layover() >= pvs_time:
                        if self.stops[1].layover() >= pdc_time:
                            start_check = True

        if not start_check:
            return False

        # check stop PVS and P&DC
        stop_check = False
        if self.same_name:
            if self.stops[-1].stop_name == pvs_name:
                if self.stops[-1].layover() == layover_time:
                    stop_check = True
        else:
            if self.stops[-1].stop_name == pvs_name:
                if self.stops[-2].stop_name == pdc_name:
                    if self.stops[-1].layover() >= pvs_time:
                        if self.stops[-2].layover() >= pdc_time:
                            stop_check = True

        if not stop_check:
            return False

        # check lunch situation
        break_time = 0
        lunch_check = False
        duration = self.duration_postalized()
        if duration < hours_wo_lunch * 60:
            lunch_check = True
        elif duration <= lunch_duration + hours_wo_lunch * 120:
            if self.has_good_lunch(lunch_duration, hours_wo_lunch):
                lunch_check = True
                lunch_stop = next(x for x in self.stops if x.stop_name in ("LUNCH", "Lunch"))
                break_time += lunch_stop.layover()
        else:
            print("too long for lunch")

        if not lunch_check:
            return False

        work_time = duration - break_time
        if work_time > max_working_time * 60:
            return False

        return True