|  | @@ -0,0 +1,235 @@
 | 
	
		
			
				|  |  | +import typing
 | 
	
		
			
				|  |  | +import sqlalchemy
 | 
	
		
			
				|  |  | +import sqlalchemy.engine.base
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +from .app_route import app_route_database
 | 
	
		
			
				|  |  | +from .product import product 
 | 
	
		
			
				|  |  | +from .product_loader import product_loader
 | 
	
		
			
				|  |  | +from .exception import bad_request_exception
 | 
	
		
			
				|  |  | +from .exception import not_found_exception
 | 
	
		
			
				|  |  | +from .exception import access_denied_exception
 | 
	
		
			
				|  |  | +from .exception import database_exception
 | 
	
		
			
				|  |  | +from .exception import incorrect_target_exception
 | 
	
		
			
				|  |  | +from .users_collection import users_collection
 | 
	
		
			
				|  |  | +from .reservation import reservation 
 | 
	
		
			
				|  |  | +from .reservation import reservation_factory
 | 
	
		
			
				|  |  | +from .reservation_loader import reservation_loader
 | 
	
		
			
				|  |  | +from .deep_request import deep_request
 | 
	
		
			
				|  |  | +from .reservations_collection import reservations_collection
 | 
	
		
			
				|  |  | +from .reservations_response import reservations_response
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class reservation_deep_request(deep_request):
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def has_product(self) -> bool:  
 | 
	
		
			
				|  |  | +        return self.target_barcode is not None or self.target_name is not None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property 
 | 
	
		
			
				|  |  | +    def has_email(self) -> bool:
 | 
	
		
			
				|  |  | +        return self.email is not None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def has_phone_number(self) -> bool:
 | 
	
		
			
				|  |  | +        return self.phone_number is not None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def has_apikey(self) -> bool:
 | 
	
		
			
				|  |  | +        return self.apikey is not None
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +class reservation_app(app_route_database):
 | 
	
		
			
				|  |  | +    def __init__(
 | 
	
		
			
				|  |  | +        self,
 | 
	
		
			
				|  |  | +        connection: sqlalchemy.engine.base.Engine,
 | 
	
		
			
				|  |  | +        users: users_collection
 | 
	
		
			
				|  |  | +    ) -> None:
 | 
	
		
			
				|  |  | +        super().__init__(connection)
 | 
	
		
			
				|  |  | +        self.__users_collection = users
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def get_by_user(self, params: dict) -> dict:
 | 
	
		
			
				|  |  | +        request = reservation_deep_request(params)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            with self.__reservation_loader as loader:
 | 
	
		
			
				|  |  | +                collection = self.__load_by_user(request, loader)
 | 
	
		
			
				|  |  | +                self.__reservation_user_filter(collection, request)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                reservations_list = reservations_response() \
 | 
	
		
			
				|  |  | +                    .collection(collection.results())
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                return self._success(reservations = reservations_list)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        except Exception as error:
 | 
	
		
			
				|  |  | +            return self.__catch(error)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def get_by_product(self, params: dict) -> dict:
 | 
	
		
			
				|  |  | +        request = reservation_deep_request(params)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            self.__login(request)
 | 
	
		
			
				|  |  | +            item = self.__load_product(request)
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            with self.__reservation_loader as loader:
 | 
	
		
			
				|  |  | +                collection = loader.get_by_target(item) 
 | 
	
		
			
				|  |  | +                self.__reservation_user_filter(collection, request)
 | 
	
		
			
				|  |  | + 
 | 
	
		
			
				|  |  | +                reservations_list = reservations_response() \
 | 
	
		
			
				|  |  | +                    .collection(collection.results())
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                return self._success(reservations = reservations_list)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        except Exception as error:
 | 
	
		
			
				|  |  | +            return self.__catch(error)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def rent_product(self, params: dict) -> dict:
 | 
	
		
			
				|  |  | +        request = reservation_deep_request(params)
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            self.__login(request)
 | 
	
		
			
				|  |  | +            item = self.__load_product(request)
 | 
	
		
			
				|  |  | +            rent = self.__create_factory(request).target(item).result()
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            with self.__reservation_loader as loader:
 | 
	
		
			
				|  |  | +                if not loader.store(rent):
 | 
	
		
			
				|  |  | +                    raise database_exception()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return self._success()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        except Exception as error:
 | 
	
		
			
				|  |  | +            return self.__catch(error)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def give_back_product(self, params: dict) -> dict:
 | 
	
		
			
				|  |  | +        request = reservation_deep_request(params)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        try:
 | 
	
		
			
				|  |  | +            self.__login(request)
 | 
	
		
			
				|  |  | +            target = self.__get_reservation(request)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            with self.__reservation_loader as loader:
 | 
	
		
			
				|  |  | +                if loader.drop(target):
 | 
	
		
			
				|  |  | +                    return self._success()
 | 
	
		
			
				|  |  | +                
 | 
	
		
			
				|  |  | +                raise database_exception()
 | 
	
		
			
				|  |  | +        
 | 
	
		
			
				|  |  | +        except Exception as error:
 | 
	
		
			
				|  |  | +            return self.__catch(error)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __reservation_user_filter(
 | 
	
		
			
				|  |  | +        self, 
 | 
	
		
			
				|  |  | +        collection: reservations_collection, 
 | 
	
		
			
				|  |  | +        request: deep_request
 | 
	
		
			
				|  |  | +    ) -> bool:
 | 
	
		
			
				|  |  | +        if not request.has_email and not request.has_phone_number:
 | 
	
		
			
				|  |  | +            return False
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if request.has_email:
 | 
	
		
			
				|  |  | +            collection.by_email(request.email)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if request.has_phone_number:
 | 
	
		
			
				|  |  | +            collection.by_phone_number(request.phone_number)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __reservation_product_filter(
 | 
	
		
			
				|  |  | +        self,
 | 
	
		
			
				|  |  | +        collection: reservations_collection,
 | 
	
		
			
				|  |  | +        request: deep_request
 | 
	
		
			
				|  |  | +    ) -> bool:
 | 
	
		
			
				|  |  | +        if not request.has_product:
 | 
	
		
			
				|  |  | +            return False
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        item = self.__load_product(request)
 | 
	
		
			
				|  |  | +        collection.by_target(item)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return True
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __get_reservation(self, request: deep_request) -> reservation:
 | 
	
		
			
				|  |  | +        with self.__reservation_loader as loader:
 | 
	
		
			
				|  |  | +            item = self.__load_product(request)
 | 
	
		
			
				|  |  | +            collection = loader.get_by_target(item)
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            if not self.__reservation_user_filter(collection, request):
 | 
	
		
			
				|  |  | +                raise bad_request_exception("Not contaim email or phone")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            result = collection.results()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if len(result) == 0:    
 | 
	
		
			
				|  |  | +                raise not_found_exception()
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            if len(result) > 1:
 | 
	
		
			
				|  |  | +                raise incorrect_target_exception("Found too much targets.")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            return result[0]
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __load_by_user(
 | 
	
		
			
				|  |  | +        self, 
 | 
	
		
			
				|  |  | +        request: deep_request,
 | 
	
		
			
				|  |  | +        loader: reservation_loader
 | 
	
		
			
				|  |  | +    ) -> reservations_collection:
 | 
	
		
			
				|  |  | +        if request.has_email:
 | 
	
		
			
				|  |  | +            return loader.get_by_email(request.email)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if request.has_phone_number:
 | 
	
		
			
				|  |  | +            return loader.get_by_phone_number(request.phone_number)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        raise bad_request_exception("Has no email or phone number")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __create_factory(self, request: deep_request) -> reservation_factory:
 | 
	
		
			
				|  |  | +        if not request.has_email and not request.has_phone_number:
 | 
	
		
			
				|  |  | +            raise bad_request_exception("Not contain email or/and phone")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        factory = reservation_factory()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if request.has_email:
 | 
	
		
			
				|  |  | +            factory.email(request.email)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if request.has_phone_number:
 | 
	
		
			
				|  |  | +            factory.phone_number(request.phone_number)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        return factory
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __login(self, request: deep_request) -> None:
 | 
	
		
			
				|  |  | +        if not request.has_apikey:
 | 
	
		
			
				|  |  | +            raise access_denied_exception()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if self.__users_collection.get(request.apikey):
 | 
	
		
			
				|  |  | +            return 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        raise access_denied_exception()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __load_product(self, request: deep_request) -> product:  
 | 
	
		
			
				|  |  | +        if request.target_barcode is not None:
 | 
	
		
			
				|  |  | +            return self.__product_by_barcode(request)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        if request.target_name is not None:
 | 
	
		
			
				|  |  | +            return self.__product_by_name(request)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        raise bad_request_exception("Not contain barcode or name")
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __product_by_barcode(self, request: deep_request) -> product:
 | 
	
		
			
				|  |  | +        with self.__product_loader as loader:
 | 
	
		
			
				|  |  | +            product = loader.get_by_barcode(request.target_barcode)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if product is not None:
 | 
	
		
			
				|  |  | +                return product
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            raise not_found_exception()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __product_by_name(self, request: deep_request) -> product:
 | 
	
		
			
				|  |  | +        with self.__product_loader as loader:
 | 
	
		
			
				|  |  | +            product = loader.get_by_name(request.target_name) 
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            if product is not None:
 | 
	
		
			
				|  |  | +                return product
 | 
	
		
			
				|  |  | +            
 | 
	
		
			
				|  |  | +            raise not_found_exception()
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    def __catch(self, error: Exception) -> dict:
 | 
	
		
			
				|  |  | +        return self._fail(str(error))
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def __reservation_loader(self):
 | 
	
		
			
				|  |  | +        return reservation_loader(self._connection)
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +    @property
 | 
	
		
			
				|  |  | +    def __product_loader(self):
 | 
	
		
			
				|  |  | +        return product_loader(self._connection)
 | 
	
		
			
				|  |  | +        
 |