def test_get_overlapping_tables_declined_and_done_reservations(self):
     res_time = time(hour=12, minute=30)
     res_date = datetime.now().date()
     res_datetime = datetime.combine(res_date, res_time)
     with self.app.app_context():
         #restaurant = db.session.query(Restaurant).filter_by(id=2).first()
         overlapping_tables = cr.get_overlapping_tables(
             restaurant_id=self.restaurants[2]['id'],
             reservation_time=res_datetime,
             reservation_seats=6,
             avg_stay_time=self.restaurants[2]['avg_stay_time'])
         self.assertEqual(0, len(overlapping_tables))
    def test_assign_table_to_reservation(self):
        res_time_free = time(hour=21, minute=00)
        res_date_free = datetime.now().date()
        res_datetime_free = datetime.combine(res_date_free, res_time_free)
        res_seats_free = 3

        res_tables_free = [t['table_id'] for t in self.restaurants[0]['tables'] if t['seats'] == res_seats_free]

        res_time_none = time(hour=13, minute=00)
        res_date_none = datetime.now().date()
        res_datetime_none = datetime.combine(res_date_none, res_time_none)
        res_seats_none = 5

        res_tables_none = [t['table_id'] for t in self.restaurants[1]['tables'] if t['seats'] == res_seats_none]

        with self.app.app_context():
            #restaurant_free = db.session.query(Restaurant).filter_by(
             #   id=1).first()
            overlapping_tables_free = cr.get_overlapping_tables(
                restaurant_id=self.restaurants[0]['id'],
                reservation_time=res_datetime_free,
                reservation_seats=res_seats_free,
                avg_stay_time=self.restaurants[0]['avg_stay_time'])
            
            assigned_table_1 = cr.assign_table_to_reservation(
                overlapping_tables=overlapping_tables_free,
                restaurant_tables=res_tables_free)

            #restaurant_none = db.session.query(Restaurant).filter_by(
            #    id=2).first()
            overlapping_tables_none = cr.get_overlapping_tables(
                restaurant_id=self.restaurants[1]['id'],
                reservation_time=res_datetime_none,
                reservation_seats=res_seats_none,
                avg_stay_time=self.restaurants[1]['avg_stay_time'])
            assigned_table_2 = cr.assign_table_to_reservation(
                overlapping_tables=overlapping_tables_none,
                restaurant_tables=res_tables_none)
        self.assertEqual(1, assigned_table_1)
        self.assertIsNone(assigned_table_2)
 def test_get_ovelapping_tables_restaurant2(self):
     res_time = time(hour=13, minute=00)
     res_date = datetime.now().date()
     res_datetime = datetime.combine(res_date, res_time)
     with self.app.app_context():
         #restaurant = db.session.query(Restaurant).filter_by(id=2).first()
         overlapping_tables = cr.get_overlapping_tables(
             restaurant_id= self.restaurants[1]['id'],
             reservation_time=res_datetime,
             reservation_seats=5,
             avg_stay_time=self.restaurants[1]['avg_stay_time'])
     self.assertEqual(1, len(overlapping_tables))
     self.assertEqual(4, overlapping_tables[0])
    def test_is_overbooked(self):
        res_time_1 = time(hour=13, minute=00)
        res_date_1 = datetime.now().date()
        res_datetime_1 = datetime.combine(res_date_1, res_time_1)
        res_seats_1 = 5
        #mock the response from restaurant service
        res_tables_1 = [t['table_id'] for t in self.restaurants[1]['tables'] if t['seats'] == res_seats_1]

        res_time_2 = time(hour=21, minute=00)
        res_date_2 = datetime.now().date()
        res_datetime_2 = datetime.combine(res_date_2, res_time_2)
        res_seats_2 = 3
        #mock the response from restaurant service
        res_tables_2 = [t['table_id'] for t in self.restaurants[0]['tables'] if t['seats'] == res_seats_2]

        with self.app.app_context():
            #restaurant_1 = db.session.query(Restaurant).filter_by(id=2).first()
            overlapping_tables_1 = cr.get_overlapping_tables(
                restaurant_id=self.restaurants[1]['id'],
                reservation_time=res_datetime_1,
                reservation_seats=res_seats_1,
                avg_stay_time=self.restaurants[1]['avg_stay_time'])
            overbooked_1 = cr.is_overbooked(
                overlapping_tables=overlapping_tables_1,
                restaurant_tables=res_tables_1)

            #restaurant_2 = db.session.query(Restaurant).filter_by(id=1).first()
            overlapping_tables_2 = cr.get_overlapping_tables(
                restaurant_id=self.restaurants[0]['id'],
                reservation_time=res_datetime_2,
                reservation_seats=res_seats_2,
                avg_stay_time=self.restaurants[0]['avg_stay_time'])
            overbooked_2 = cr.is_overbooked(
                overlapping_tables=overlapping_tables_2,
                restaurant_tables=res_tables_2)
        self.assertEqual(True, overbooked_1)
        self.assertEqual(False, overbooked_2)
def update_user_reservation(reservation_id: int):
    req_body = request.get_json()
    new_seats = req_body['new_seats']
    new_time = datetime.fromisoformat(req_body['new_reservation_time'])

    try:
        reservation = db.session.query(Reservation).filter_by(
            id=reservation_id).first()
        if reservation is None:
            return {'message': 'Reservation not found'}, 404
    except DatabaseError as exc:
        return {'message': str(exc)}, 500

    try:
        response = requests.get(
            f'http://{os.environ.get("GOS_RESTAURANT")}/restaurants/{reservation.restaurant_id}'
        )
        restaurant = None if response.status_code != 200 else response.json()
        if response.status_code == 404:
            return {'message': 'Restaurant not found'}, 404
    except:
        restaurant = None
    if (restaurant != None):
        avg_stay_time = datetime.strptime(restaurant['avg_stay_time'],
                                          '%H:%M:%S').time()
        if (req_body['new_seats'] == reservation.seats and
                cr.is_safely_updatable(reservation, avg_stay_time, new_time)):
            reservation.reservation_time = new_time
            reservation.status = ReservationState.PENDING
            try:
                db.session.commit()
                return {'message': 'Reservation updated correctly'}, 200
            except DatabaseError as exc:
                return str(exc), 500
        else:
            try:
                overlapping_tables = cr.get_overlapping_tables(
                    restaurant_id=reservation.restaurant_id,
                    reservation_time=new_time,
                    reservation_seats=new_seats,
                    avg_stay_time=avg_stay_time)
            except DatabaseError as exc:
                return str(exc), 500
            try:
                table_response = requests.get(
                    f'http://{os.environ.get("GOS_RESTAURANT")}/restaurants/tables/{reservation.restaurant_id}?seats={new_seats}'
                )
                if table_response.status_code == 404:
                    return {
                        'message':
                        'No tables with the wanted number of seats available'
                    }, 404
                tables = None if table_response.status_code != 200 else table_response.json(
                )['tables']
            except:
                if table_response.status_code == 404:
                    return {
                        'message':
                        'No tables with the wanted number of seats available'
                    }, 404
                tables = None
            if (tables != None):
                ids = [table['table_id'] for table in tables]
                print(ids)
                if (cr.is_overbooked(overlapping_tables, ids)):
                    return {
                        'message':
                        'Overbooking: no tables available at the requested date and time'
                    }, 409
                else:
                    assigned = cr.assign_table_to_reservation(
                        overlapping_tables, ids)
                    reservation.reservation_time = new_time
                    reservation.table_no = assigned
                    reservation.seats = new_seats
                    reservation.status = ReservationState.PENDING
                    try:
                        db.session.commit()
                        return {
                            'message': 'Reservation updated correctly'
                        }, 200
                    except DatabaseError as exc:
                        return str(exc), 500
            else:
                return {'message': 'Restaurant service unavailable'}, 500
    else:
        return {'message': 'Restaurant service unavailable'}, 500
def reserve():
    req_body = request.get_json()
    try:
        response = requests.get(
            f'http://{os.environ.get("GOS_RESTAURANT")}/restaurants/{req_body["restaurant_id"]}'
        )
        restaurant = None if response.status_code != 200 else response.json()
        if response.status_code == 404:
            return {'message': 'Restaurant not found'}, 404
    except requests.exceptions.RequestException as exc:
        restaurant = None
    if restaurant is not None:
        avg_stay_time = datetime.strptime(restaurant['avg_stay_time'],
                                          '%H:%M:%S').time()
        try:
            overlapping_tables = cr.get_overlapping_tables(
                restaurant_id=req_body['restaurant_id'],
                reservation_time=datetime.fromisoformat(
                    req_body['reservation_time']),
                reservation_seats=req_body['seats'],
                avg_stay_time=avg_stay_time)
        except DatabaseError as exc:
            return {'message': str(exc)}, 500
        try:
            table_response = requests.get(
                f'http://{os.environ.get("GOS_RESTAURANT")}/restaurants/tables/{req_body["restaurant_id"]}?seats={req_body["seats"]}'
            )
            if table_response.status_code == 404:
                return {
                    'message':
                    'No tables with the wanted number of seats available'
                }, 404
            tables = None if response.status_code != 200 else table_response.json(
            )['tables']
            print(tables)
        except:
            tables = None
        if tables is not None:
            ids = [table['table_id'] for table in tables]
            print(cr.is_overbooked(overlapping_tables, ids))
            if (cr.is_overbooked(overlapping_tables, ids)):
                return {
                    'message':
                    'Overbooking: no tables available at the requested date and time'
                }, 409
            else:
                assigned = cr.assign_table_to_reservation(
                    overlapping_tables, ids)
                reservation = Reservation(
                    user_id=req_body['user_id'],
                    restaurant_id=req_body['restaurant_id'],
                    reservation_time=datetime.fromisoformat(
                        req_body['reservation_time']),
                    seats=req_body['seats'],
                    table_no=assigned)
                try:
                    id = cr.add_reservation(reservation)
                    return {'id': id}, 200
                except DatabaseError as exc:
                    return {'message': str(exc)}, 500
        else:
            return {'message': 'Restaurant service unavailable'}, 500
    else:
        return {'message': 'Restaurant service unavailable'}, 500