def load_departments():
    """
    Loads departments from connected Uber instance
    :return:
    """
    REQUEST_HEADERS = {'X-Auth-Token': cfg.uber_authkey}

    # data being sent to API
    request_data = {'method': 'dept.list'}
    request = requests.post(url=cfg.api_endpoint,
                            json=request_data,
                            headers=REQUEST_HEADERS)
    response = json.loads(request.text)
    response = response['result'].items()

    # print('loading departments')
    session = models.new_sesh()
    for dept in response:
        try:
            mydept = session.query(Department).filter_by(id=dept[0]).one()
            if not mydept.name == dept[1]:
                mydept.name = dept[1]
        except sqlalchemy.orm.exc.NoResultFound:
            mydept = Department()
            mydept.id = dept[0]
            mydept.name = dept[1]
            session.add(mydept)

    session.commit()
    session.close()
    return
def dummy_data(count, startorder):
    """
    create dummy data for testing
    :return:
    """
    session = models.new_sesh()
    count = int(count)
    depts = session.query(Department).all()
    meals = session.query(models.meal.Meal).all()
    # attendees = session.query(models.attendee.Attendee).all()

    i = 0
    while i < count:
        order = copy.deepcopy(startorder)

        attend = models.attendee.Attendee()
        attend.public_id = str(uuid.uuid4())
        session.add(attend)
        order.attendee_id = attend.public_id

        meal = random.choice(meals)
        order.meal_id = meal.id

        dept = random.choice(depts)
        order.department_id = dept.id

        session.add(order)
        i += 1

    session.commit()
    session.close()
def ss_eligible(badge_num):
    """
    Looks up attendee badge number in Uber and returns whether they are eligible to use Staff Suite.
    General eligiblity to get food, not eligiblity for any specific meal
    :param badge_num: attendee's badge number for lookup
    :return: returns True or False
    """

    response = lookup_attendee(badge_num, full=True)
    
    if "error" in response:
        print('------------Error looking up attendee eligibility for ' + badge_num + ' --------------')
        return False
    
    attendee = response['result']
    
    # attendees who have have already worked required hours for eligibility
    if attendee['worked_hours'] >= cfg.ss_hours:
        return True

    # non-staff who are signed up for at least <current year's hours req> and have worked at least one shift
    if attendee['badge_type_label'] == "Attendee":
        if attendee['weighted_hours'] >= cfg.ss_hours:
            if attendee['worked_hours'] > 0:
                return True

    # Guests and Contractors automatically get access
    if attendee['badge_type_label'] in ["Guest", "Contractor", "Staff"]:
        return True

    # Department Heads always get access
    if response['result']['is_dept_head']:
        return True

    # Staff who have signed up for at least <event required> hours.
    # Having already worked a shift this event not required for people with Staff status
    # if attendee['badge_type_label'] == "Staff":
      #   if attendee["weighted_hours"] >= cfg.ss_hours:
        #     return True

    if response['result']['public_id'] in cfg.food_managers:
        return True

    session = models.new_sesh()

    if is_vip(attendee['badge_num'], session):
        return True

    # shiftless departments are exempt from eligibility requirements
    depts = session.query(models.department.Department).filter_by(is_shiftless=True).all()
    for dept in depts:
        if dept.name in attendee['assigned_depts_labels']:
            return True

    # if nothing above matches, not eligible.
    return False
def is_vip(badge, session=None):
    """
    Checks if provided badge is in VIP list
    """
    if not session:
        session = models.new_sesh()

    vip_list = session.query(models.attendee.Attendee).filter_by(is_vip=True).all()
    for vip in vip_list:
        if badge == vip.badge_num:
            return True

    return False
def get_vip_list():
    """
    Returns list of VIPs formated as "badge_num, full_name" string
    """
    session = models.new_sesh()

    vips = session.query(models.attendee.Attendee).filter_by(is_vip=True).order_by(models.attendee.Attendee.badge_num).all()

    vip_list = list()

    for vip in vips:
        vip_list.append(str(vip.badge_num) + ", " + vip.full_name)

    return vip_list
def dummy_data(count, startorder):
    """
    create dummy data for testing
    :startorder: starting order is provided so some basic fields can be valid without having to be filled out.
    :return:
    """

    # do not want to create dummy data in live DB!!!

    if cfg.env == "prod":
        print("-----------Tried to create dummy data but this server is marked as live!-----------")
        return

    session = models.new_sesh()
    count = int(count)
    depts = session.query(Department).all()
    meals = session.query(models.meal.Meal).all()
    
    i = 0
    while i < count:
        order = copy.deepcopy(startorder)
        
        attend = models.attendee.Attendee()
        attend.public_id = str(uuid.uuid4())
        session.add(attend)
        order.attendee_id = attend.public_id
        
        meal = random.choice(meals)
        order.meal_id = meal.id
        
        dept = random.choice(depts)
        order.department_id = dept.id
        
        session.add(order)
        i += 1
    
    session.commit()
    session.close()
    return
def load_departments():
    """
    Loads departments from connected Uber instance
    :return:
    """
    REQUEST_HEADERS = {'X-Auth-Token': cfg.uber_authkey}

    request_data = {'method': 'dept.list'}
    request = requests.post(url=cfg.api_endpoint, json=request_data, headers=REQUEST_HEADERS)
    response = json.loads(request.text)
    response = response['result'].items()

    session = models.new_sesh()
    for dept in response:
        try:
            mydept = session.query(Department).filter_by(id=dept[0]).one()

            if not mydept.name == dept[1]:
                mydept.name = dept[1]

        except sqlalchemy.orm.exc.NoResultFound:
            mydept = Department()
            mydept.id = dept[0]
            mydept.name = dept[1]
            session.add(mydept)

        request_data = {'method': 'dept.jobs', "params": {"department_id": dept[0]}}
        request = requests.post(url=cfg.api_endpoint, json=request_data, headers=REQUEST_HEADERS)
        dept_details = json.loads(request.text)

        # this checks if changed before updating because my memory tells me
        # fewer changed records makes the SQL commit faster
        if not mydept.is_shiftless == dept_details['result']['is_shiftless']:
            mydept.is_shiftless = dept_details['result']['is_shiftless']
            
    session.commit()
    session.close()
    return
def carryout_eligible(shifts, response, meal_start, meal_end):
    """
    Takes a list of shifts and checks if they overlap the given meal period
    Uses rules for allowable gaps configured in system
    :param shifts: List of shift objects. Concurrent shifts must already be merged or this will not work correctly!
    :param response : full response from attendee lookup from Uber API
    :param meal_start : date object for the meal start in python dateutil datetime format
    :param meal_end : date object for the meal end in python dateutil datetime format
    :return: returns True or False
    """
    # need to check combined if shift starts within <<buffer>> after start of meal time or earlier
    # AND ends within <<buffer>exc> before end of meal time or later

    """code section for buffer, commented out cause not using buffer for Super 2020
    meal_buffer = relativedelta(minutes=cfg.schedule_tolerance)
    # print("Meal start: {} Meal End {}".format(str(meal_start),str(meal_end)))
    
    for shift in shifts:
        # print("shift start : {} Shift end: {}".format(str(shift.start),str(shift.end)))
        sdelta = relativedelta((meal_start + meal_buffer), shift.start)
        start_delta = sdelta.minutes + (sdelta.hours * 60)
        
        edelta = relativedelta(shift.end, (meal_end - meal_buffer))
        end_delta = edelta.minutes + (edelta.hours * 60)
        
        if start_delta >= 0 and end_delta >= 0 and sdelta.days == 0:
            # start_delta.days being anything other than 0 means the shift is more than 24 hours from the meal
            return True
    """
    # rd is negative if first before second
    # ss=shift start, se = shift end.  ms=meal start, me= meal end
    # if ss after ms AND before me then good
    # if se after ms AND before me then good
    # if ss before ms AND se after me then good
    # if the shift is more than a day before or after the meal days != 0

    # if there are no shifts, skip processing
    if len(shifts) != 0:
        # this code checks for if shift start during meal period
        # this will also catch entire shifts that happen inside part of meal period
        for shift in shifts:
            ss_ms = relativedelta(meal_start, shift.start)
            ss_ms_delta = ss_ms.minutes + (ss_ms.hours * 60)
            ss_me = relativedelta(meal_end, shift.start)
            ss_me_delta = ss_me.minutes + (ss_me.hours * 60)
            if ss_ms_delta < 0 and ss_me_delta > 0 and ss_ms.days == 0:
                # print('ss after ms AND before me then good')
                return True

            # this code checks for if shift end during meal period
            se_ms = relativedelta(meal_start, shift.end)
            se_ms_delta = se_ms.minutes + (se_ms.hours * 60)
            se_me = relativedelta(meal_end, shift.end)
            se_me_delta = se_me.minutes + (se_me.hours * 60)
            if se_ms_delta < 0 and se_me_delta > 0 and ss_ms.days == 0:
                # print('se after ms AND before me then good')
                return True

            # this code checks for if shift start is before/= AND shift end is after/= meal period
            # this will also catch shifts that happen during the exact start and end time of the meal period
            if ss_ms_delta >= 0 and se_me_delta <= 0 and ss_ms.days == 0:
                # print('if ss before ms AND se after me then good')
                return True

    if response['result']['is_dept_head']:
        return True

    if response['result']['badge_type_label'] in ["Contractor", "Guest"]:
        return True

    if response['result']['public_id'] in cfg.food_managers:
        return True

    session = models.new_sesh()

    if is_vip(response['result']['badge_num'], session):
        return True

    shiftless_depts = session.query(models.department.Department).filter_by(is_shiftless=True).all()
    for dept in shiftless_depts:
        if dept.name in response['result']['assigned_depts_labels']:
            session.close()
            return True

    session.close()
    # if none of the shifts match the meal period and attendee is not exempt, return false.
    return False
def add_access(badge, usertype=None):
    """
    Adds provided badge number (or barcode) to selected access list
    :param badge:
    :param usertype: 'admin' or 'staff' or 'food_manager'
    :return:
    """
    if badge[0] == "~":
        badge = barcode_to_badge(badge)
    else:
        try:
            badge = int(badge)
        except ValueError:
            raise HTTPRedirect("Not a number?")

    if not badge:
        raise HTTPRedirect("config?message=Badge not found")

    session = models.new_sesh()
   
    try:
        attend = session.query(models.attendee.Attendee).filter_by(badge_num=badge).one()
    except sqlalchemy.orm.exc.NoResultFound:
        response = lookup_attendee(badge)
        if 'error' in response:
            session.close()
            # admin or staff would be added using config page, Food Manager would be from dept_orders page
            if usertype == 'admin' or usertype == 'staff':
                raise HTTPRedirect("config?message=Badge " + str(badge) + " is not found in Reggie")
            else:
                raise HTTPRedirect("dept_order_selection?message=Badge " + str(badge) + " is not found in Reggie")
        
        attend = models.attendee.Attendee()
        attend.badge_num = response['result']['badge_num']
        attend.public_id = response['result']['public_id']
        attend.full_name = response['result']['full_name']
        session.add(attend)
        session.commit()

    if usertype == 'admin' and attend.public_id not in cfg.admin_list:
        cfg.admin_list.append(attend.public_id)
    if usertype == 'staff' and attend.public_id not in cfg.staffer_list:
        cfg.staffer_list.append(attend.public_id)
    if usertype == 'food_manager' and attend.public_id not in cfg.food_managers:
        if is_dh(attend.public_id):
            session.close()
            raise HTTPRedirect("dept_order_selection?message=Badge " + str(badge) + "is already a Department Head")
        if is_admin(attend.public_id):
            session.close()
            raise HTTPRedirect("dept_order_selection?message=Badge " + str(badge) + "is already a Tuber Eats Admin")

        cfg.food_managers.append(attend.public_id)
        manager_list = ',\n'.join(cfg.food_managers)
        managerfile = open('food_managers.cfg', 'w')
        managerfile.write(manager_list)
        managerfile.close()
        session.close()
        return True
        
    session.close()
    return False