reservation_app.py 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. import typing
  2. import sqlalchemy
  3. import sqlalchemy.engine.base
  4. from .app_route import app_route_database
  5. from .product import product
  6. from .product_loader import product_loader
  7. from .exception import bad_request_exception
  8. from .exception import not_found_exception
  9. from .exception import access_denied_exception
  10. from .exception import database_exception
  11. from .exception import incorrect_target_exception
  12. from .users_collection import users_collection
  13. from .reservation import reservation
  14. from .reservation import reservation_factory
  15. from .reservation_loader import reservation_loader
  16. from .deep_request import deep_request
  17. from .reservations_collection import reservations_collection
  18. from .reservations_response import reservations_response
  19. class reservation_deep_request(deep_request):
  20. @property
  21. def has_product(self) -> bool:
  22. return self.target_barcode is not None or self.target_name is not None
  23. @property
  24. def has_email(self) -> bool:
  25. return self.email is not None
  26. @property
  27. def has_phone_number(self) -> bool:
  28. return self.phone_number is not None
  29. @property
  30. def has_apikey(self) -> bool:
  31. return self.apikey is not None
  32. class reservation_app(app_route_database):
  33. def __init__(
  34. self,
  35. connection: sqlalchemy.engine.base.Engine,
  36. users: users_collection
  37. ) -> None:
  38. super().__init__(connection)
  39. self.__users_collection = users
  40. def get_by_user(self, params: dict) -> dict:
  41. request = reservation_deep_request(params)
  42. try:
  43. with self.__reservation_loader as loader:
  44. collection = self.__load_by_user(request, loader)
  45. self.__reservation_user_filter(collection, request)
  46. reservations_list = reservations_response() \
  47. .collection(collection.results())
  48. return self._success(reservations = reservations_list)
  49. except Exception as error:
  50. return self.__catch(error)
  51. def get_by_product(self, params: dict) -> dict:
  52. request = reservation_deep_request(params)
  53. try:
  54. self.__login(request)
  55. item = self.__load_product(request)
  56. with self.__reservation_loader as loader:
  57. collection = loader.get_by_target(item)
  58. self.__reservation_user_filter(collection, request)
  59. reservations_list = reservations_response() \
  60. .collection(collection.results())
  61. return self._success(reservations = reservations_list)
  62. except Exception as error:
  63. return self.__catch(error)
  64. def rent_product(self, params: dict) -> dict:
  65. request = reservation_deep_request(params)
  66. try:
  67. self.__login(request)
  68. item = self.__load_product(request)
  69. rent = self.__create_factory(request).target(item).result()
  70. with self.__reservation_loader as loader:
  71. if not self.__product_avairable(item):
  72. raise bad_request_exception("Item already not avairable")
  73. if not loader.store(rent):
  74. raise database_exception()
  75. return self._success()
  76. except Exception as error:
  77. return self.__catch(error)
  78. def give_back_product(self, params: dict) -> dict:
  79. request = reservation_deep_request(params)
  80. try:
  81. self.__login(request)
  82. target = self.__get_reservation(request)
  83. with self.__reservation_loader as loader:
  84. if loader.drop(target):
  85. return self._success()
  86. raise database_exception()
  87. except Exception as error:
  88. return self.__catch(error)
  89. def __reservation_user_filter(
  90. self,
  91. collection: reservations_collection,
  92. request: deep_request
  93. ) -> bool:
  94. if not request.has_email and not request.has_phone_number:
  95. return False
  96. if request.has_email:
  97. collection.by_email(request.email)
  98. if request.has_phone_number:
  99. collection.by_phone_number(request.phone_number)
  100. return True
  101. def __reservation_product_filter(
  102. self,
  103. collection: reservations_collection,
  104. request: deep_request
  105. ) -> bool:
  106. if not request.has_product:
  107. return False
  108. item = self.__load_product(request)
  109. collection.by_target(item)
  110. return True
  111. def __get_reservation(self, request: deep_request) -> reservation:
  112. with self.__reservation_loader as loader:
  113. item = self.__load_product(request)
  114. collection = loader.get_by_target(item)
  115. if not self.__reservation_user_filter(collection, request):
  116. raise bad_request_exception("Not contaim email or phone")
  117. result = collection.results()
  118. if len(result) == 0:
  119. raise not_found_exception()
  120. if len(result) > 1:
  121. raise incorrect_target_exception("Found too much targets.")
  122. return result[0]
  123. def __load_by_user(
  124. self,
  125. request: deep_request,
  126. loader: reservation_loader
  127. ) -> reservations_collection:
  128. if request.has_email:
  129. return loader.get_by_email(request.email)
  130. if request.has_phone_number:
  131. return loader.get_by_phone_number(request.phone_number)
  132. raise bad_request_exception("Has no email or phone number")
  133. def __create_factory(self, request: deep_request) -> reservation_factory:
  134. if not request.has_email and not request.has_phone_number:
  135. raise bad_request_exception("Not contain email or/and phone")
  136. factory = reservation_factory()
  137. if request.has_email:
  138. factory.email(request.email)
  139. if request.has_phone_number:
  140. factory.phone_number(request.phone_number)
  141. return factory
  142. def __login(self, request: deep_request) -> None:
  143. if not request.has_apikey:
  144. raise access_denied_exception()
  145. if self.__users_collection.get(request.apikey):
  146. return
  147. raise access_denied_exception()
  148. def __load_product(self, request: deep_request) -> product:
  149. if request.target_barcode is not None:
  150. return self.__product_by_barcode(request)
  151. if request.target_name is not None:
  152. return self.__product_by_name(request)
  153. raise bad_request_exception("Not contain barcode or name")
  154. def __product_by_barcode(self, request: deep_request) -> product:
  155. with self.__product_loader as loader:
  156. product = loader.get_by_barcode(request.target_barcode)
  157. if product is not None:
  158. return product
  159. raise not_found_exception()
  160. def __product_avairable(self, target: product) -> bool:
  161. with self.__product_loader as loader:
  162. return loader.get_by_barcode(target.barcode).on_stock > 0
  163. def __product_by_name(self, request: deep_request) -> product:
  164. with self.__product_loader as loader:
  165. product = loader.get_by_name(request.target_name)
  166. if product is not None:
  167. product.on_stock
  168. return product
  169. raise not_found_exception()
  170. def __catch(self, error: Exception) -> dict:
  171. return self._fail(str(error))
  172. @property
  173. def __reservation_loader(self):
  174. return reservation_loader(self._connection)
  175. @property
  176. def __product_loader(self):
  177. return product_loader(self._connection)