schemas.py 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302
  1. from pydantic import BaseModel, EmailStr, Field, ConfigDict
  2. from typing import Optional, List
  3. from datetime import datetime
  4. # Response models
  5. class MaterialBase(BaseModel):
  6. id: int
  7. name_en: Optional[str] = None
  8. name_ru: Optional[str] = None
  9. name_ua: Optional[str] = None
  10. name_me: Optional[str] = None
  11. desc_en: Optional[str] = None
  12. desc_ru: Optional[str] = None
  13. desc_ua: Optional[str] = None
  14. desc_me: Optional[str] = None
  15. long_desc_en: Optional[str] = None
  16. long_desc_ru: Optional[str] = None
  17. long_desc_ua: Optional[str] = None
  18. long_desc_me: Optional[str] = None
  19. service_id: Optional[int] = None
  20. price_per_cm3: float
  21. price_per_hour: Optional[float] = None
  22. speed_coeff: Optional[float] = 1.0
  23. available_colors: Optional[List[str]] = None
  24. is_active: bool
  25. class ServiceBase(BaseModel):
  26. id: int
  27. name_en: Optional[str] = None
  28. name_ru: Optional[str] = None
  29. name_ua: Optional[str] = None
  30. name_me: Optional[str] = None
  31. desc_en: Optional[str] = None
  32. desc_ru: Optional[str] = None
  33. desc_ua: Optional[str] = None
  34. desc_me: Optional[str] = None
  35. tech_type: Optional[str] = None
  36. price_per_hour: Optional[float] = None
  37. is_active: bool
  38. # Management models
  39. class MaterialCreate(BaseModel):
  40. name_en: str
  41. name_ru: str
  42. name_ua: str
  43. name_me: str
  44. desc_en: str
  45. desc_ru: str
  46. desc_ua: str
  47. desc_me: str
  48. long_desc_en: Optional[str] = ""
  49. long_desc_ru: Optional[str] = ""
  50. long_desc_ua: Optional[str] = ""
  51. long_desc_me: Optional[str] = ""
  52. service_id: Optional[int] = None
  53. price_per_cm3: float
  54. price_per_hour: Optional[float] = 0.0
  55. speed_coeff: Optional[float] = 1.0
  56. available_colors: Optional[List[str]] = None
  57. is_active: bool = True
  58. class MaterialUpdate(BaseModel):
  59. name_en: Optional[str] = None
  60. name_ru: Optional[str] = None
  61. name_ua: Optional[str] = None
  62. name_me: Optional[str] = None
  63. desc_en: Optional[str] = None
  64. desc_ru: Optional[str] = None
  65. desc_ua: Optional[str] = None
  66. desc_me: Optional[str] = None
  67. long_desc_en: Optional[str] = None
  68. long_desc_ru: Optional[str] = None
  69. long_desc_ua: Optional[str] = None
  70. long_desc_me: Optional[str] = None
  71. price_per_cm3: Optional[float] = None
  72. price_per_hour: Optional[float] = None
  73. speed_coeff: Optional[float] = None
  74. service_id: Optional[int] = None
  75. available_colors: Optional[List[str]] = None
  76. is_active: Optional[bool] = None
  77. class ServiceCreate(BaseModel):
  78. name_en: str
  79. name_ru: str
  80. name_ua: str
  81. name_me: str
  82. desc_en: str
  83. desc_ru: str
  84. desc_ua: str
  85. desc_me: str
  86. tech_type: Optional[str] = None
  87. price_per_hour: Optional[float] = 0.0
  88. is_active: bool = True
  89. class ServiceUpdate(BaseModel):
  90. name_en: Optional[str] = None
  91. name_ru: Optional[str] = None
  92. name_ua: Optional[str] = None
  93. name_me: Optional[str] = None
  94. desc_en: Optional[str] = None
  95. desc_ru: Optional[str] = None
  96. desc_ua: Optional[str] = None
  97. desc_me: Optional[str] = None
  98. tech_type: Optional[str] = None
  99. price_per_hour: Optional[float] = None
  100. is_active: Optional[bool] = None
  101. # Order creation models
  102. class OrderFileBase(BaseModel):
  103. filename: str
  104. file_size: Optional[int]
  105. class OrderCreate(BaseModel):
  106. first_name: str = Field(..., min_length=1)
  107. last_name: str = Field(..., min_length=1)
  108. phone: str = Field(..., min_length=5)
  109. email: EmailStr
  110. shipping_address: str = Field(..., min_length=10)
  111. model_link: Optional[str] = None
  112. quantity: int = Field(1, ge=1)
  113. notes: Optional[str] = None
  114. material_id: int
  115. color_name: Optional[str] = None
  116. # User models
  117. class UserCreate(BaseModel):
  118. email: EmailStr
  119. password: str = Field(..., min_length=6)
  120. first_name: Optional[str] = None
  121. last_name: Optional[str] = None
  122. phone: Optional[str] = None
  123. shipping_address: Optional[str] = None
  124. preferred_language: Optional[str] = "en"
  125. is_company: bool = False
  126. company_name: Optional[str] = None
  127. company_pib: Optional[str] = None
  128. company_address: Optional[str] = None
  129. class UserUpdate(BaseModel):
  130. first_name: Optional[str] = None
  131. last_name: Optional[str] = None
  132. phone: Optional[str] = None
  133. shipping_address: Optional[str] = None
  134. preferred_language: Optional[str] = None
  135. can_chat: Optional[bool] = None
  136. is_active: Optional[bool] = None
  137. is_company: Optional[bool] = None
  138. company_name: Optional[str] = None
  139. company_pib: Optional[str] = None
  140. company_address: Optional[str] = None
  141. class AdminUserUpdate(UserUpdate):
  142. role: Optional[str] = None
  143. password: Optional[str] = Field(None, min_length=6)
  144. class UserLogin(BaseModel):
  145. email: EmailStr
  146. password: str
  147. captcha_token: Optional[str] = None
  148. class UserResponse(BaseModel):
  149. id: int
  150. email: EmailStr
  151. first_name: Optional[str] = None
  152. last_name: Optional[str] = None
  153. phone: Optional[str] = None
  154. shipping_address: Optional[str] = None
  155. preferred_language: str = "en"
  156. role: str
  157. can_chat: bool
  158. is_active: bool
  159. is_company: bool
  160. company_name: Optional[str] = None
  161. company_pib: Optional[str] = None
  162. company_address: Optional[str] = None
  163. ip_address: Optional[str] = None
  164. created_at: datetime
  165. model_config = ConfigDict(from_attributes=True)
  166. class AdminOrderUpdate(BaseModel):
  167. status: Optional[str] = None
  168. total_price: Optional[float] = None
  169. material_id: Optional[int] = None
  170. material_name: Optional[str] = None
  171. color_name: Optional[str] = None
  172. quantity: Optional[int] = None
  173. send_notification: Optional[bool] = False
  174. fiscal_qr_url: Optional[str] = None
  175. ikof: Optional[str] = None
  176. jikr: Optional[str] = None
  177. # Customer data
  178. first_name: Optional[str] = None
  179. last_name: Optional[str] = None
  180. email: Optional[EmailStr] = None
  181. phone: Optional[str] = None
  182. shipping_address: Optional[str] = None
  183. notes: Optional[str] = None
  184. # Review management
  185. review_text: Optional[str] = None
  186. rating: Optional[int] = None
  187. review_approved: Optional[bool] = None
  188. class EstimateRequest(BaseModel):
  189. material_id: int
  190. file_sizes: List[int] # in bytes
  191. file_quantities: Optional[List[int]] = None
  192. # Possible to add density or other params later
  193. class Token(BaseModel):
  194. access_token: str
  195. token_type: str
  196. from typing import Optional, List, Any
  197. class SocialLogin(BaseModel):
  198. provider: str # 'google'
  199. token: str
  200. email: Any = None
  201. first_name: Any = None
  202. last_name: Any = None
  203. preferred_language: Any = "en"
  204. class ForgotPassword(BaseModel):
  205. email: EmailStr
  206. class ResetPassword(BaseModel):
  207. token: str
  208. new_password: str = Field(..., min_length=6)
  209. class PhotoUpdate(BaseModel):
  210. is_public: bool
  211. caption: Optional[str] = None
  212. class OrderResponse(OrderCreate):
  213. id: int
  214. status: str
  215. total_price: Optional[float] = None
  216. estimated_price: Optional[float] = None
  217. material_name: Optional[str] = None
  218. material_price: Optional[float] = None
  219. material_id: Optional[int] = None
  220. color_name: Optional[str] = None
  221. original_params: Optional[str] = None
  222. created_at: datetime
  223. # Review fields
  224. review_text: Optional[str] = None
  225. rating: Optional[int] = 0
  226. review_approved: bool = False
  227. model_config = ConfigDict(from_attributes=True)
  228. class OrderReview(BaseModel):
  229. rating: int = Field(..., ge=1, le=5)
  230. review_text: str = Field(..., min_length=2)
  231. class PublicReview(BaseModel):
  232. first_name: str
  233. rating: Optional[int] = 0
  234. review_text: Optional[str] = None
  235. class MessageCreate(BaseModel):
  236. message: str
  237. class ContactRequest(BaseModel):
  238. name: str = Field(..., min_length=1)
  239. email: EmailStr
  240. subject: str = Field(..., min_length=1)
  241. message: str = Field(..., min_length=1)
  242. class TokenVerify(BaseModel):
  243. token: str
  244. # Warehouse models
  245. class WarehouseItemBase(BaseModel):
  246. material_id: int
  247. color_name: str
  248. quantity: float = 0.0 # Total weight
  249. unit_mass: float = 1.0 # Weight of one unit (e.g. 1kg spool)
  250. units_count: float = 0.0 # Number of units (e.g. 1.5 spools)
  251. notes: Optional[str] = None
  252. is_active: bool = True
  253. class WarehouseItemCreate(WarehouseItemBase):
  254. pass
  255. class WarehouseItemUpdate(BaseModel):
  256. material_id: Optional[int] = None
  257. color_name: Optional[str] = None
  258. quantity: Optional[float] = None
  259. unit_mass: Optional[float] = None
  260. units_count: Optional[float] = None
  261. notes: Optional[str] = None
  262. is_active: Optional[bool] = None
  263. class WarehouseItemResponse(WarehouseItemBase):
  264. id: int
  265. material_name_en: str
  266. created_at: datetime
  267. updated_at: datetime
  268. model_config = ConfigDict(from_attributes=True)