product.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. import sqlmodel
  2. from .exception import validator_exception
  3. from .validator import name_validator
  4. from .validator import description_validator
  5. from .validator import barcode_validator
  6. from .validator import author_validator
  7. class product(sqlmodel.SQLModel, table = True):
  8. """
  9. This class is product model in database. Product is item, which could be
  10. shared.
  11. """
  12. """ Name of the table to use in foreign keys. """
  13. __tablename__: str = "product"
  14. """ ID of the product in the database. """
  15. id: int | None = sqlmodel.Field(default = None, primary_key = True)
  16. """ Name of the product, or title of the book. """
  17. name: str | None = sqlmodel.Field(
  18. default = None,
  19. index = True,
  20. unique = True
  21. )
  22. """ Description of the product, provided by creator. """
  23. description: str | None = sqlmodel.Field(default = None)
  24. """ Author of the product. """
  25. author: str | None = sqlmodel.Field(default = None)
  26. """ Count of instances this products in stock. """
  27. stock_count: int = sqlmodel.Field(default = 0)
  28. """ This is barcode (EAN) of the product. """
  29. barcode: str | None = sqlmodel.Field(
  30. default = None,
  31. index = True,
  32. unique = True
  33. )
  34. reservations: list["reservation"] = sqlmodel.Relationship(
  35. back_populates = "target"
  36. )
  37. @property
  38. def on_stock(self) -> int:
  39. current = self.stock_count - len(self.reservations)
  40. if current < 0:
  41. return 0
  42. return current
  43. @property
  44. def avairable(self) -> bool:
  45. return self.on_stock > 0
  46. def save_copy(self) -> object:
  47. """
  48. This return clone of the product, which is not connect with
  49. database.
  50. Returns:
  51. (product): Clone of the product, which is not database connected
  52. """
  53. result = product()
  54. result.name = self.name
  55. result.description = self.description
  56. result.author = self.author
  57. result.stock_count = self.stock_count
  58. result.barcode = self.barcode
  59. return result
  60. def restore_copy(self, target: object) -> object:
  61. """
  62. This restore content of the product, from the save copy.
  63. Parameters:
  64. target (product): Target product to restore
  65. Returns:
  66. (product): Return product itself
  67. """
  68. self.name = target.name
  69. self.description = target.description
  70. self.author = target.author
  71. self.stock_count = target.stock_count
  72. self.barcode = target.barcode
  73. return self
  74. @property
  75. def in_database(self) -> bool:
  76. """ This return True when product exists in database. """
  77. return self.id is not None
  78. @property
  79. def avairable(self) -> bool:
  80. """ This check that item is avairable on stock. """
  81. return self.stock_count > 0
  82. def __str__(self) -> str:
  83. """
  84. This dump product to string, which is helpfull when debug.
  85. Returns:
  86. (str): Product as string dump
  87. """
  88. content = str(self.name) + " "
  89. if self.in_database:
  90. content = content + "#" + str(self.id)
  91. content = content + "\n"
  92. content = content + "Description: " + str(self.description) + "\n"
  93. content = content + "Author: " + str(self.author) + "\n"
  94. content = content + "Barcode (EAN): " + str(self.barcode) + "\n"
  95. content = content + "In stock: " + str(self.stock_count) + "\n"
  96. return content
  97. @property
  98. def ready(self) -> bool:
  99. """ Check that product is ready to insert into database. """
  100. if self.name is None or self.description is None:
  101. return False
  102. if self.barcode is None or self.author is None:
  103. return False
  104. return True
  105. class product_factory:
  106. """
  107. This is builder of the product. It helps to handle validation of the
  108. product params, and modify exists product with validators.
  109. """
  110. def __init__(self, target: product | None = None) -> None:
  111. """
  112. This create new builder. When get already created item, it work on
  113. given once. When receive None, create new product to work on.
  114. Parameters:
  115. target (product | None): Item to work on (default: None)
  116. """
  117. if target is not None:
  118. self.__target = target
  119. return
  120. self.__target = product()
  121. @property
  122. def ready(self) -> bool:
  123. """ It return True when target is ready to insert into database. """
  124. return self.__target.ready
  125. @property
  126. def result(self) -> product:
  127. """ It return ready product, or raise Exception if not Ready yet. """
  128. if not self.__target.ready:
  129. raise Exception("Product in builder is not ready yet.")
  130. return self.__target
  131. @property
  132. def name(self) -> str | None:
  133. """ It return name of the product. """
  134. return self.__target.name
  135. @name.setter
  136. def name(self, target: str) -> None:
  137. """ It set name of the product, and validating it. """
  138. if name_validator(target).invalid:
  139. raise validator_exception("product.name")
  140. self.__target.name = target
  141. @property
  142. def description(self) -> str | None:
  143. """ This return product description. """
  144. return self.__target.description
  145. def add_to_stock(self) -> None:
  146. """
  147. This add one item to stock.
  148. """
  149. self.__target.stock_count += 1
  150. def get_from_stock(self) -> bool:
  151. """
  152. This get single item from stock.
  153. Returns:
  154. (bool): True when get success, false when not avairable
  155. """
  156. if not self.__target.avairable:
  157. return False
  158. self.__target.stock_count -= 1
  159. return True
  160. @description.setter
  161. def description(self, target: str) -> None:
  162. """ This set description of the product, and validate it."""
  163. if description_validator(target).invalid:
  164. raise validator_exception("product.description")
  165. self.__target.description = target
  166. @property
  167. def barcode(self) -> str | None:
  168. """ It return barcode of building product. """
  169. return self.__target.barcode
  170. @barcode.setter
  171. def barcode(self, target: str) -> None:
  172. """ This set new barcode, and validate it. """
  173. if barcode_validator(target).invalid:
  174. raise validator_exception("product.barcode")
  175. self.__target.barcode = target
  176. @property
  177. def author(self) -> str | None:
  178. """ This return author of the product. """
  179. return self.__target.author
  180. @author.setter
  181. def author(self, target: str) -> None:
  182. """ This validate author of the product, and set it. """
  183. if author_validator(target).invalid:
  184. raise validator_exception("product.author")
  185. self.__target.author = target
  186. @property
  187. def stock_count(self) -> int:
  188. """ This return how much product is in stock. """
  189. return self.__target.stock_count
  190. @stock_count.setter
  191. def stock_count(self, target: int) -> None:
  192. """ This set stock count of the product, it mut be positive number. """
  193. if target < 0:
  194. raise validator_exception("product.stock_count")
  195. self.__target.stock_count = target