Skip to content
Snippets Groups Projects
router.py 16.7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Lukas Köhler's avatar
    Lukas Köhler committed
    import uuid
    from typing import List, Optional, TypeVar
    
    Lukas Köhler's avatar
    Lukas Köhler committed
    from fastapi import APIRouter, Depends, Request, Response, status, HTTPException
    from fastapi.responses import RedirectResponse
    from sqlalchemy.orm import Session
    
    import app.api.v1.endpoints.beverage.crud as beverage_crud
    import app.api.v1.endpoints.order.crud as order_crud
    import app.api.v1.endpoints.order.stock_logic.stock_beverage_crud as stock_beverage_crud
    import app.api.v1.endpoints.order.stock_logic.stock_ingredients_crud as stock_ingredients_crud
    import app.api.v1.endpoints.pizza_type.crud as pizza_type_crud
    import app.api.v1.endpoints.user.crud as user_crud
    from app.api.v1.endpoints.order.schemas \
        import OrderSchema, PizzaCreateSchema, JoinedPizzaPizzaTypeSchema, \
        PizzaWithoutPizzaTypeSchema, OrderBeverageQuantityCreateSchema, JoinedOrderBeverageQuantitySchema, \
    
        OrderPriceSchema, OrderBeverageQuantityBaseSchema, OrderCreateSchema, OrderStatus
    
    Lukas Köhler's avatar
    Lukas Köhler committed
    from app.api.v1.endpoints.user.schemas import UserSchema
    from app.database.connection import SessionLocal
    
    router = APIRouter()
    
    
    def get_db():
        db = SessionLocal()
        try:
            yield db
        finally:
            db.close()
    
    
    @router.get('', response_model=List[OrderSchema], tags=['order'])
    def get_all_orders(
            db: Session = Depends(get_db),
    ):
        orders = order_crud.get_all_orders(db)
        return orders
    
    
    Omar Ibrahim Arfa's avatar
    Omar Ibrahim Arfa committed
    
    
    @router.get('/{order_status}', response_model=List[OrderSchema], tags=['order'])
    def get_filtered_orders(
            db: Session = Depends(get_db),
    
    Omar Ibrahim Arfa's avatar
    Omar Ibrahim Arfa committed
            order_status = OrderStatus,
    
    ):
        orderUpperString = str(order_status).upper()
        order_status = getattr(OrderStatus, orderUpperString)
        orders = order_crud.get_filtered_orders(db, order_status)
        return orders
    
    
    Lukas Köhler's avatar
    Lukas Köhler committed
    
    @router.post('', response_model=OrderSchema, status_code=status.HTTP_201_CREATED, tags=['order'])
    def create_order(order: OrderCreateSchema, db: Session = Depends(get_db),
                     copy_order_id: Optional[uuid.UUID] = None):
        if user_crud.get_user_by_id(order.user_id, db) is None:
            raise HTTPException(status_code=404, detail='Item not found')
    
        # Create Order
        new_order = order_crud.create_order(order, db)
    
        # Check if Copy Order is specified
        if copy_order_id is None:
    
            logging.info('Created order {}'.format(new_order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return new_order
    
        # Check Copy Order
        copy_order = order_crud.get_order_by_id(copy_order_id, db)
        if not copy_order:
    
            logging.error('Cannot Create because Original Order {} does not exits'.format(copy_order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            order_crud.delete_order_by_id(new_order.id, db)
            raise HTTPException(status_code=404, detail='Item not found')
    
        # Copy Pizzas
        for pizza in copy_order.pizzas:
            pizza_type = pizza.pizza_type
            if not stock_ingredients_crud.ingredients_are_available(pizza_type):
                # Not enough Stock
    
                logging.error('Cannot Create Order {} because not enough stock for Pizza {}'
                              .format(new_order.id, pizza.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
                order_crud.delete_order_by_id(new_order.id, db)
                raise HTTPException(status_code=409, detail='Conflict')
    
            logging.debug('Successfully copied Pizzas to Order {}'.format(new_order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            order_crud.add_pizza_to_order(new_order, pizza_type, db)
            stock_ingredients_crud.reduce_stock_of_ingredients(pizza_type, db)
    
        # Copy Beverages
        for beverage_quantity in copy_order.beverages:
            schema = OrderBeverageQuantityCreateSchema(
                **{'quantity': beverage_quantity.quantity, 'beverage_id': beverage_quantity.beverage_id})
            if not stock_beverage_crud.change_stock_of_beverage(beverage_quantity.beverage_id,
                                                                -beverage_quantity.quantity, db):
                # Not enough Stock
    
                logging.error('Cannot Create Order {} because not enough stock for Beverage {}'
                              .format(new_order.id, beverage_quantity.beverage_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
                order_crud.delete_order_by_id(new_order.id, db)
                raise HTTPException(status_code=409, detail='Conflict')
    
            order_crud.create_beverage_quantity(new_order, schema, db)
    
            logging.debug('Successfully copied Beverages to Order {}'.format(new_order.id))
        logging.info('Successfully new Order {} (copy)'.format(new_order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return new_order
    
    
    @router.get('/{order_id}', response_model=OrderSchema, tags=['order'])
    def get_order(
            order_id: uuid.UUID,
            db: Session = Depends(get_db)):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot Get Order {}, it does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        logging.info('GET Order {}'.format(order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return order
    
    
    @router.delete('/{order_id}', response_model=None, tags=['order'])
    def delete_order(
            order_id: uuid.UUID,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot Delete Order {}, it does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        ordered_pizzas = order.pizzas
        if ordered_pizzas:
            for pizza in ordered_pizzas:
                stock_ingredients_crud.increase_stock_of_ingredients(pizza.pizza_type, db)
        order_beverages = order_crud.get_joined_beverage_quantities_by_order(order_id, db)
        if order_beverages:
            for order_beverage in order_beverages:
                stock_beverage_crud.change_stock_of_beverage(order_beverage.beverage.id, order_beverage.quantity, db)
    
        logging.info('Delete Order {}'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        order_crud.delete_order_by_id(order_id, db)
        return Response(status_code=status.HTTP_204_NO_CONTENT)
    
    
    @router.post('/{order_id}/pizzas', response_model=PizzaWithoutPizzaTypeSchema, tags=['order'])
    def add_pizza_to_order(
            order_id: uuid.UUID,
            schema: PizzaCreateSchema,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        if not order:
    
            logging.error('Cannot Add Pizza_Type to Order {}, Order does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        pizza_type = pizza_type_crud.get_pizza_type_by_id(schema.pizza_type_id, db)
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        if not pizza_type:
    
            logging.error('Cannot Add Pizza_Type {} to Order {}, Pizza_type does not exist'
                          .format(schema.pizza_type_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        if not stock_ingredients_crud.ingredients_are_available(pizza_type):
    
            logging.error('Cannot Add Pizza_Type {} to Order {}, not enough Pizza ingredients'
                          .format(schema.pizza_type_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_409_CONFLICT)
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        stock_ingredients_crud.reduce_stock_of_ingredients(pizza_type, db)
        pizza = order_crud.add_pizza_to_order(order, pizza_type, db)
    
    
        logging.info('Add Pizza_Type {} to Order {}'.format(schema.pizza_type_id, order_id))
    
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return pizza
    
    
    @router.get('/{order_id}/pizzas', response_model=List[JoinedPizzaPizzaTypeSchema], tags=['order'])
    def get_pizzas_from_order(
            order_id: uuid.UUID,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot GET Pizzas from Order {}, Order does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        pizzas = order_crud.get_all_pizzas_of_order(order, db)
    
        logging.info('GET Pizzas from Order {}'.format(order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return pizzas
    
    
    @router.delete('/{order_id}/pizzas', response_model=None, tags=['order'])
    def delete_pizza_from_order(
            order_id: uuid.UUID,
            pizza: PizzaWithoutPizzaTypeSchema,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot Delete Pizza {} from Order {}, Order does not exist'.format(pizza.id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        pizza_entity = order_crud.get_pizza_by_id(pizza.id, db)
        if not pizza_entity:
    
            logging.error('Cannot Delete Pizza {} from Order {}, Pizza does not exist'.format(pizza.id, order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        stock_ingredients_crud.increase_stock_of_ingredients(pizza_entity.pizza_type, db)
    
        logging.debug('Successfully increased ingredients for Pizza_type {} from Order {}'
                      .format(pizza.id, order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
    
        if not order_crud.delete_pizza_from_order(order, pizza.id, db):
    
            logging.critical('Failed to Delete Pizza {} from Order {}'.format(pizza.id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
    
        logging.info('Delete Pizza {} from Order {}'.format(pizza.id, order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return Response(status_code=status.HTTP_200_OK)
    
    
    # Due to mypy error, this workaround is needed for Union
    # see pull request https://github.com/python/mypy/pull/8779
    # should be fixed in near future
    MyPyEitherItem = TypeVar(
        'MyPyEitherItem',
        List[OrderBeverageQuantityCreateSchema],
        List[JoinedOrderBeverageQuantitySchema],
        None,
    )
    
    
    @router.get(
        '/{order_id}/beverages',
        response_model=MyPyEitherItem,
        tags=['order'],
    )
    def get_order_beverages(
            order_id: uuid.UUID,
            db: Session = Depends(get_db),
            join: bool = False,
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot GET Beverages from Order {}, Order does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        order = order_crud.get_order_by_id(order_id, db)
    
        beverages = order.beverages
        if join:
            beverages = order_crud.get_joined_beverage_quantities_by_order(order.id, db)
    
        logging.info('GET Beverages from Order {}'.format(order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return beverages
    
    
    @router.post(
        '/{order_id}/beverages',
        response_model=OrderBeverageQuantityCreateSchema,
        status_code=status.HTTP_201_CREATED,
        tags=['order'],
    )
    def create_order_beverage(
            order_id: uuid.UUID,
            beverage_quantity: OrderBeverageQuantityCreateSchema,
            request: Request,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot Add Beverage to Order {}, Order does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        # Check if new Quantity is valid
        if beverage_quantity.quantity <= 0:
    
            logging.error('Cannot Add Beverage to Order {}, invalid quantity'.format(order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=422)
    
        beverage = beverage_crud.get_beverage_by_id(beverage_quantity.beverage_id, db)
        if not beverage:
    
            logging.error('Cannot Add Beverage {} to Order {}, Beverage does not exist'
                          .format(beverage_quantity.beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=404, detail='Item not found')
    
        beverage_quantity_found = order_crud.get_beverage_quantity_by_id(order_id, beverage_quantity.beverage_id, db)
        if beverage_quantity_found:
    
            logging.info('Add Beverage to Order {} (Redirect)'.format(order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            url = request.url_for('get_order_beverages', order_id=beverage_quantity_found.order_id)
            return RedirectResponse(url=url, status_code=status.HTTP_303_SEE_OTHER)
        # Change Stock of Beverage if enough is available
        if not stock_beverage_crud.beverage_is_available(beverage_quantity.beverage_id, beverage_quantity.quantity, db):
    
            logging.error('Failed to Add Beverage {} to Order {}, not enough stock'
                          .format(beverage_quantity.beverage_id, order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=409, detail='Conflict')
        stock_beverage_crud.change_stock_of_beverage(beverage_quantity.beverage_id, -beverage_quantity.quantity, db)
    
        logging.debug('Successfully changed stock of Beverage {}'.format(beverage_quantity.beverage_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        new_beverage_quantity = order_crud.create_beverage_quantity(order, beverage_quantity, db)
    
        logging.info('Add Beverage {} to Order {}'.format(new_beverage_quantity.beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return new_beverage_quantity
    
    
    @router.put(
        '/{order_id}/beverages',
        response_model=OrderBeverageQuantityBaseSchema,
        tags=['order'],
    )
    def update_beverage_of_order(
            order_id: uuid.UUID,
            beverage_quantity: OrderBeverageQuantityCreateSchema,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot Update Beverage from Order {}, Order does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        # Check if new Quantity is valid
        if beverage_quantity.quantity <= 0:
    
            logging.error('Cannot Update Beverages from Order {}, invalid quantity'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
    
        beverage_id = beverage_quantity.beverage_id
        order_beverage_quantity = order_crud.get_beverage_quantity_by_id(order_id, beverage_id, db)
        if not order_beverage_quantity:
    
            logging.error('Cannot Update Beverage {} from Order {}, quantity not found'.format(beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=404, detail='Item not found')
        new_quantity = beverage_quantity.quantity
        old_quantity = order_beverage_quantity.quantity
        # Change Stock if enough is available: change Amount is Previous - New
        if not stock_beverage_crud.change_stock_of_beverage(beverage_id, old_quantity - new_quantity, db):
    
            logging.error('Cannot Update Beverage {} quantity from Order {}, not enough stock'
                          .format(beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=409, detail='Conflict')
        # Update
        new_order_beverage_quantity = order_crud.update_beverage_quantity_of_order(
            order_id, beverage_quantity.beverage_id, beverage_quantity.quantity, db)
        # Return updated OrderBeverageQuantity
        if new_order_beverage_quantity:
    
            logging.info('Update Beverage {} quantity from Order {}'.format(beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return new_order_beverage_quantity
        else:
    
            logging.critical('Failed to Update Beverage {} quantity from Order {}'.format(beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=404, detail='Item not found')
    
    
    @router.delete(
        '/{order_id}/beverages', response_model=None, tags=['order'],
    )
    def delete_beverage_from_order(
            order_id: uuid.UUID,
            beverage_id: uuid.UUID,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot Delete Beverage {} from Order {}, Order does not exist'.format(beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        order_beverage = order_crud.get_beverage_quantity_by_id(order_id, beverage_id, db)
        if not order_beverage:
    
            logging.error('Cannot Delete Beverage {} from Order {}, Beverage does not exist'.format(beverage_id, order.id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            raise HTTPException(status_code=404, detail='Item not found')
        # Increase Stock by the quantity of the deleted order
        order_quantity = order_beverage.quantity
        stock_beverage_crud.change_stock_of_beverage(beverage_id, order_quantity, db)
    
        logging.debug('Increased Beverage {} Stock quantity'.format(beverage_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        # Delete OrderBeverageQuantity
    
        logging.info('Delete Beverage {} from Order {}'.format(beverage_id, order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        order_crud.delete_beverage_from_order(order_id, beverage_id, db)
        return Response(status_code=status.HTTP_204_NO_CONTENT)
    
    
    @router.get(
        '/{order_id}/price',
        status_code=status.HTTP_200_OK,
        response_model=OrderPriceSchema,
        tags=['order'],
    )
    def get_price_of_order(
            order_id: uuid.UUID,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
    
            logging.error('Cannot GET Price of Order {}, Order does not exist'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        price = order_crud.get_price_of_order(order_id, db)
    
        logging.info('GET Price of Order {}'.format(order_id))
    
    Lukas Köhler's avatar
    Lukas Köhler committed
        return OrderPriceSchema(**{
            'price': price,
        })
    
    
    @router.get('/{order_id}/user',
                status_code=status.HTTP_200_OK,
                response_model=UserSchema,
                tags=['order'],
                )
    def get_user_of_order(
            order_id: uuid.UUID,
            db: Session = Depends(get_db),
    ):
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
            return Response(status_code=status.HTTP_404_NOT_FOUND)
    
        order = order_crud.get_order_by_id(order_id, db)
        if not order:
            raise HTTPException(status_code=404, detail='Item not found')
        user = order.user
        return user