예제 #1
0
def templates():
    if request.method == "GET":
        org_id = 1
        templates = Shift.create_templates(1)
        json_templates = json.dumps(templates)
        return render_template("templates.html",params={})

    if request.method == "POST":
        org_id = 1 # get from user
        chosen_template = 1 # get from user
        Shift.create_from_template(org_id, chosen_template)  # create shifts in DB
예제 #2
0
def send_hours_info():
    try:
        if request.method == "GET":
            org_id = 1  # get user's org_id
            start_date = datetimeHelp.next_weekday(dt.today(),
                                                   6)  # next week's Sunday
            end_date = datetimeHelp.next_weekday(dt.today(),
                                                 12)  # next week's Saturday
            raw_shifts = db.get_shifts_by_date_range(org_id, start_date,
                                                     end_date)
            shifts = [
                Shift(shift[0], shift[1], shift[2]) for shift in raw_shifts
            ]
            return str([json.dumps(s.__dict__) for s in shifts])

        if request.method == "POST":
            # match the user's days request
            user_id = request.form["user_id"]
            dates = request.form[
                "dates"]  # convert days to date - accepted format YYYY-MM-DD  HH:MM
            start_time = request.form["hours"]
            end_time = "NULL"
            # change arrangement and employee logic to handle multiple hour choice,
            for date in dates:
                db.insert_employee_times(user_id, date, start_time, end_time)

            flash("Shift options recorded successfully")
            return redirect("/send_hours")
            # session.pop('_flashes', None)
            # flash("Attendance failed to register")
    except IOError:
        print("Error fetching information")
예제 #3
0
def arrangement_info():
    if request.method == "GET":
        # make sure start_date is before end_date
        user_id = 1  # get logged in user's ID
        same_day_scheduling = False  # get this from user
        start_date = "1-1-2020"  # get this from user
        # start_date = str(datetimeHelp.next_weekday(dt.today(), 6)) - date of next Sunday
        end_date = "7-1-2020"  # get this from user
        # end_time = str(datetimeHelp.next_weekday(dt.today(), 12)) - date of next Saturday
        org_id = db.get_org_by_usr(user_id)[0][0]  # get user org_id
        sol_num = db.sol_exists(org_id)  # gets the max sol number from DB
        if sol_num[0]:  # if solution exists in DB
            session["sol"] = sol_num[0] + 1
        else:
            session["sol"] += 1
        raw_employees = db.get_employees_by_date_range(org_id, start_date, end_date)
        employees = Employee.create_from_DB(raw_employees)
        raw_shifts = db.get_shifts_by_date_range(org_id, start_date, end_date)
        shifts = Shift.create_from_DB(raw_shifts)
        raw_workdays = db.get_wdays_by_date_range(org_id, start_date, end_date)
        workdays = WorkDay.create_from_DB(org_id, raw_workdays)

        # add shifts to corresponding days
        for shift in shifts:
            for i in range(len(workdays)):
                if shift.get_date() == workdays[i].get_date():
                    workdays[i].add_shift(shift)

        ww = WorkWeek(workdays)
        dic, sol = ww.create_arrangement(employees, same_day_scheduling)
        employees, shifts = ww.extract_solution(sol)
        mat = Matrix(employees, shifts)
        # dic is a dictionary that maps number of shifts assigned to a employee
        # sol is the actual solved arrangement
        # for example {1:[E1,E2], 2:[E3,E4]..}

        # add arrangement to DB
        # db.register_arrangement(sol, session["sol"])
        #print(WorkWeek.min_shifts_swap(dic,sol))
        # 2: [Employee 5, tom col, dict_keys(['waitress', 'bartender']), Employee 7, itzik shawarma, dict_keys(['waitress']), Employee 8, roni kofif, dict_keys(['waitress', 'bartender'])],
        # 3: [Employee 6, pagi pagi, dict_keys(['waitress', 'bartender']), Employee 4, niv mali, dict_keys(['bartender']), Employee 9, some guy, dict_keys(['waitress']), Employee 1, ben mali, dict_keys(['bartender']), Employee 2, paz mali, dict_keys(['waitress']), Employee 3, rom mali, dict_keys(['bartender'])],
        # 4: [Employee 10, another guy, dict_keys(['bartender', 'waitress'])], 5: [], 6: [], 7: [], 8: [], 9: [], 10: []}]

        #2: [Employee 5, tom col, dict_keys(['waitress', 'bartender']), Employee 7, itzik shawarma, dict_keys(['waitress']), Employee 8, roni kofif, dict_keys(['waitress', 'bartender'])],
        # 3: [Employee 6, pagi pagi, dict_keys(['waitress', 'bartender']), Employee 4, niv mali, dict_keys(['bartender']), Employee 9, some guy, dict_keys(['waitress']), Employee 1, ben mali, dict_keys(['bartender']), Employee 10, another guy, dict_keys(['bartender', 'waitress']), Employee 3, rom mali, dict_keys(['bartender'])],
        # 4: [Employee 2, paz mali, dict_keys(['waitress'])]
        #swap 2 and 10 set 10 to 4 min
        dic, solution = ww.min_shifts_swap(dic, sol)
        js_dict = {}
        for i in range(len(solution)):
            js_dict["shift {}".format(i+1)] = solution[i].get_json()
        return js_dict
    else:
        return render_template("error_page.html")
예제 #4
0
    def from_template(cls, org_id, template_no):  # for future use
        """
        initialize WorkWeek from template
        :param org_id: Org id
        :param template_no: number of template in DB user chose
        :return: WorkWeek object
        """
        try:
            db = DB("Resty.db")
            templates = db.get_ww_templates(org_id)  # get all the templates
            templates_dic = {}
            for shift in templates:
                template = shift[-1]
                if template in templates_dic:
                    templates_dic[template] += [shift]
                else:
                    templates_dic[template] = [shift]
            if template_no in templates_dic:  # user requested an existing template
                chosen_template = templates_dic[template_no]
                dates = datetimeHelp.this_week_dates()  # next week dates
                workdays = {}
                workdays_lst = []
                for shift in chosen_template:
                    if shift[0] in workdays:
                        workdays[shift[0]] += [shift]
                        # create workday
                    else:
                        workdays[shift[0]] = [shift]
                print(workdays)
                shift_id = db.get_max_shift_id(org_id)[0] + 1
                for day, shifts in workdays.items():
                    date = datetimeHelp.day_to_date(day, dates)
                    shift_lst = [
                        Shift(shift_id + i, date, shifts[i][1], shifts[i][2],
                              shifts[i][3]) for i in range(len(shifts))
                    ]
                    shift_id += len(shifts)
                    wd = WorkDay(org_id, date)
                    wd.set_shifts(shift_lst)
                    workdays_lst.append(wd)
                return cls(workdays_lst)

            else:
                print("template doesn't exist")

            # create Workdays from data, add them together to create WW

        except IOError:
            print("Failed to create template from restore")
예제 #5
0
    def create_arrangement(self, employees, same_day_scheduling=False):
        """
        get needed shifts for each day
        for each shift find number of needed staff
        get random employee and fit him to shift
        add shift to employees

        """
        """"""
        def schedule(position):
            """
            try schedule a chosen employee to shift
            :return: True if successfully scheduled Employee to Shift, False else
            """
            if shift.get_date() in chosen_employee.get_dates().keys():
                if shift.get_start_hour() in chosen_employee.get_dates()[
                        shift.get_date()]:
                    # makes sure employee isn't already scheduled to work
                    # same_day_scheduling is set to false by default
                    if chosen_employee not in day.get_employees(
                    ) or same_day_scheduling:
                        if chosen_employee not in shift.get_employees():
                            mat.set_tensor(chosen_employee,
                                           shift.get_full_time(), position)
                            chosen_employee.add_shift(shift)
                            shift_dic[i + 1] += [chosen_employee]
                            decrement_list = shift_dic[i]
                            decrement_list.remove(chosen_employee)
                            shift_dic[i] = decrement_list
                            day.add_employee(chosen_employee)
                            return True
            return False

        try:
            # same_day_scheduling is a variable that can be changed to enable same day scheduling
            # get number of employees in eligible date range
            # employees should be a dictionary, mapping between dates and available employees
            # create employee objects
            # limit the number of shifts an employee can have per week to 10
            # initialize dictionary where its' keys are number of shifts and values are list of employee ids which have
            # this number of shifts assigned
            # this method is good when you need even distribution between employees
            # create dictionary to map num of shifts per employee
            max_shifts = 10
            max_num_employees = 0  # the maximum number of scheduled employees so far
            required_employees = 0  # the number of scheduled employees needed for a full solution
            days = [day for day in self.work_days[:]]
            shifts = []
            best = []

            for day in days:
                for shift in day.get_shifts():
                    shifts.append(shift)
                    # sums up the needed number of employees to create full arrangement
                    required_employees += shift.get_num_barts(
                    ) + shift.get_num_waits()
            mat = Matrix(employees, shifts)
            for j in range(50):  # try to find solution 50 times
                num_employees = 0
                shift_dic = {
                    0: employees[:]
                }  # reset dictionary if no solution was found
                [employee.reset_shifts()
                 for employee in employees[:]]  # reset shifts for employees
                solution = []
                [day.reset_shifts() for day in self.work_days[:]]
                for i in range(1, max_shifts + 1):
                    shift_dic[i] = []
                for day in self.work_days:  # iterate over every day of the WordDay element
                    for shift in day.get_shifts(
                    ):  # iterate over every shift in the WorkDay
                        num_bartenders = shift.get_num_barts()
                        num_waitresses = shift.get_num_waits()
                        num_scheduled_bartenders, num_scheduled_waitresses = 0, 0
                        for i in range(7):
                            if num_bartenders == num_scheduled_bartenders and num_waitresses == num_scheduled_waitresses:
                                break  # scheduling shift is over, break loop
                            if shift_dic[i]:
                                possible_employees = [
                                    bartender for bartender in shift_dic[i] if
                                    "bartender" in bartender.get_positions()
                                ]
                            else:
                                continue
                            while num_bartenders > num_scheduled_bartenders:
                                if len(possible_employees) == 0:
                                    break
                                # try schedule the first strong employee found
                                if day.is_first_shift(
                                        shift) and not shift.get_bartenders():
                                    chosen_employee = Shift.get_senior_employee(
                                        shift.get_date(), "bartender", 2,
                                        possible_employees)
                                    # find a senior employee that can work at this shift
                                else:  # not the first shift of the day, fill randomly
                                    chosen_employee = random.choice(
                                        possible_employees)
                                if not chosen_employee:  # no match found for a senior employee
                                    # try schedule another employee instead, manager decision
                                    chosen_employee = random.choice(
                                        possible_employees)
                                if schedule("bartender"):
                                    shift.add_bartender(chosen_employee)

                                    num_scheduled_bartenders += 1
                                    # remove chosen employee anyway, not viable for scheduling in this shift anymore
                                possible_employees.remove(chosen_employee)

                            possible_employees = [
                                waitress for waitress in shift_dic[i]
                                if "waitress" in waitress.get_positions()
                            ]  # filter out waitresses from
                            while num_waitresses > num_scheduled_waitresses:
                                if len(possible_employees
                                       ) == 0:  # if no possible match found
                                    break
                                if day.is_first_shift(
                                        shift
                                ) and not shift.get_waitresses(
                                ):  # try schedule the first strong employee found
                                    chosen_employee = Shift.get_senior_employee(
                                        shift.get_date(), "waitress", 2,
                                        possible_employees)
                                else:  # not the first shift of the day, fill randomly
                                    chosen_employee = random.choice(
                                        possible_employees)
                                    # makes sure employee is able to work at this shift
                                if not chosen_employee:  # no match found for the employee
                                    chosen_employee = random.choice(
                                        possible_employees)
                                if schedule("waitress"):
                                    shift.add_waitress(chosen_employee)
                                    num_scheduled_waitresses += 1
                                # remove chosen employee anyway, not viable for scheduling in this shift anymore
                                possible_employees.remove(chosen_employee)
                        # end of while loops
                        solution.append(copy.deepcopy(shift))
                    num_employees += len(day.get_employees())
                if max_num_employees < num_employees:  # current solution is better than previous best
                    max_num_employees = num_employees
                    best = solution[:]
                    best_dictionary = copy.deepcopy(shift_dic)
                    print("\"\"\"\"\"")
                    print(best)
                    print("\"\"\"\"\"")
                    print("iteration: {}".format(j))

                if required_employees == num_employees:  # full solution found
                    print(mat.tensor)
                    return shift_dic, best
            print("No viable solution found - getting our best solution!")
            return best_dictionary, best

        except OverflowError:
            print("Too many loops - program shutdown")
        except IndexError:
            print("Cant create scheduling, no valid options")
예제 #6
0
                    employees.append(employee)
            shifts.append(shift)
        return employees, shifts

    def create_combinations(self, employees):
        for employee in employees:
            for date in employee.get_dates():
                pass

    # lst = list(itertools.combinations(iterable, r))


if __name__ == "__main__":
    db = DB("Resty.db")
    # --- test 2 ----#
    s1 = Shift(1, "1-1-2020", "16:00")
    s2 = Shift(2, "1-1-2020", "19:00")
    s3 = Shift(3, "2-1-2020", "16:00")
    s4 = Shift(4, "2-1-2020", "19:00")
    s5 = Shift(5, "3-1-2020", "16:00")
    s6 = Shift(6, "3-1-2020", "19:00")
    s7 = Shift(7, "4-1-2020", "16:00")
    s8 = Shift(8, "4-1-2020", "19:00")
    s9 = Shift(9, "5-1-2020", "16:00")
    s10 = Shift(10, "5-1-2020", "19:00")
    s11 = Shift(11, "6-1-2020", "16:00")
    s12 = Shift(12, "6-1-2020", "19:00")
    s13 = Shift(13, "7-1-2020", "16:00")
    s14 = Shift(14, "7-1-2020", "19:00")
    wd = WorkDay("1-1-2020", "16:00", "Tom")
    wd2 = WorkDay("2-1-2020", "16:00", "Tom")
예제 #7
0
def templates_info():
    if request.method == "GET":
        org_id = 1  # get from user
        return json.dumps(Shift.create_templates(org_id))
예제 #8
0
        dic, solution = ww.min_shifts_swap(dic, sol)
        js_dict = {}
        for i in range(len(solution)):
            js_dict["shift {}".format(i+1)] = solution[i].get_json()
        return js_dict
    else:
        return render_template("error_page.html")


if __name__ == "__main__":
    user_id = 1  # get logged in user's ID
    org_id = db.get_org_by_usr(user_id)[0][0]  # get user org_id
    #raw_employees = db.get_employees_by_date_range(org_id, "1-1-2020", "7-1-2020")
    employees = Employee.create_from_DB(db.get_employees_by_date_range(org_id, "2020-01-01", "2020-01-07"))
    raw_shifts = db.get_shifts_by_date_range(org_id, "1-1-2020", "7-1-2020")
    shifts = [Shift(shift[0], shift[1], shift[2]) for shift in raw_shifts]
    raw_workdays = db.get_wdays_by_date_range(org_id, "1-1-2020", "7-1-2020")
    workdays = [WorkDay(org_id, wd[0], wd[1]) for wd in raw_workdays]
    i = 0
    # add shifts to corresponding days
    for shift in shifts:
        while i < len(workdays):
            if shift.get_date() == workdays[i].get_date():
                workdays[i].add_shift(shift)
                break
            else:
                i += 1
    ww = WorkWeek(workdays)
    dic, sol = ww.create_arrangement(employees)
    for shift in sol:
        print(shift)