sample_freight.py 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. """样本运费批次 API"""
  2. from __future__ import annotations
  3. from typing import Any, Dict, List, Optional
  4. from fastapi import APIRouter, Depends, Query
  5. from pydantic import BaseModel, ConfigDict, Field
  6. from sqlalchemy.orm import Session
  7. from app.core.database import get_db
  8. from app.core.menu_guard import require_admin_or_super_admin
  9. from app.core.response import error_response, success_response
  10. from app.crud import sample_freight as freight_svc
  11. from app.models.models import SysUser
  12. router = APIRouter(prefix="/web/admin", tags=["样本运费批次"])
  13. def _get_tenant_no(db: Session, user: dict) -> str:
  14. user_id = user.get("user_id")
  15. if not user_id:
  16. raise PermissionError("用户身份信息缺失,无法确定租户")
  17. sys_user = db.query(SysUser).filter(SysUser.id == user_id).first()
  18. if not sys_user or not sys_user.tenant_no:
  19. raise PermissionError("用户租户信息缺失")
  20. return sys_user.tenant_no
  21. def _get_current_user_id(user: dict) -> str:
  22. user_id = user.get("user_id")
  23. if not user_id:
  24. raise PermissionError("用户身份信息缺失")
  25. return str(user_id)
  26. class SampleFreightItemBody(BaseModel):
  27. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  28. sample_source: str = Field(..., alias="sampleSource")
  29. sample_id: str = Field(..., alias="sampleId")
  30. protocol_id: Optional[str] = Field(None, alias="protocolId")
  31. sample_code: Optional[str] = Field(None, alias="sampleCode")
  32. class SampleFreightCreateBody(BaseModel):
  33. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  34. transport_mode: str = Field(..., alias="transportMode")
  35. freight_amount: float = Field(..., alias="freightAmount")
  36. items: Optional[List[SampleFreightItemBody]] = None
  37. class SampleFreightUpdateBody(BaseModel):
  38. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  39. transport_mode: Optional[str] = Field(None, alias="transportMode")
  40. freight_amount: Optional[float] = Field(None, alias="freightAmount")
  41. class SampleFreightItemsBody(BaseModel):
  42. model_config = ConfigDict(extra="ignore", populate_by_name=True)
  43. items: List[SampleFreightItemBody] = Field(default_factory=list)
  44. @router.get("/sample-freights")
  45. async def list_sample_freights(
  46. page: int = Query(1, ge=1),
  47. pageSize: int = Query(10, ge=1, le=100, alias="pageSize"),
  48. keyword: Optional[str] = None,
  49. transportMode: Optional[str] = None,
  50. sampleSource: Optional[str] = None,
  51. createTimeFrom: Optional[str] = None,
  52. createTimeTo: Optional[str] = None,
  53. includeItems: bool = Query(False),
  54. user: dict = Depends(require_admin_or_super_admin),
  55. db: Session = Depends(get_db),
  56. ):
  57. try:
  58. tenant_no = _get_tenant_no(db, user)
  59. items, total = freight_svc.list_freights(
  60. db,
  61. tenant_no=tenant_no,
  62. page=page,
  63. page_size=pageSize,
  64. keyword=keyword,
  65. transport_mode=transportMode,
  66. sample_source=sampleSource,
  67. create_time_from=createTimeFrom,
  68. create_time_to=createTimeTo,
  69. include_items=includeItems,
  70. )
  71. return success_response(
  72. {"list": items, "total": total, "page": page, "pageSize": pageSize}
  73. )
  74. except PermissionError as e:
  75. return error_response(403, str(e))
  76. except ValueError as e:
  77. return error_response(400, str(e))
  78. @router.get("/sample-freights/sample-options")
  79. async def list_sample_freight_options(
  80. page: int = Query(1, ge=1),
  81. pageSize: int = Query(20, ge=1, le=100, alias="pageSize"),
  82. keyword: Optional[str] = None,
  83. sampleSource: Optional[str] = None,
  84. user: dict = Depends(require_admin_or_super_admin),
  85. db: Session = Depends(get_db),
  86. ):
  87. try:
  88. tenant_no = _get_tenant_no(db, user)
  89. items, total = freight_svc.list_sample_options(
  90. db,
  91. tenant_no=tenant_no,
  92. page=page,
  93. page_size=pageSize,
  94. keyword=keyword,
  95. sample_source=sampleSource,
  96. )
  97. return success_response(
  98. {"list": items, "total": total, "page": page, "pageSize": pageSize}
  99. )
  100. except PermissionError as e:
  101. return error_response(403, str(e))
  102. except ValueError as e:
  103. return error_response(400, str(e))
  104. @router.get("/sample-freights/{freight_id}")
  105. async def get_sample_freight(
  106. freight_id: str,
  107. user: dict = Depends(require_admin_or_super_admin),
  108. db: Session = Depends(get_db),
  109. ):
  110. try:
  111. tenant_no = _get_tenant_no(db, user)
  112. data = freight_svc.get_freight_detail(db, freight_id, tenant_no)
  113. return success_response(data)
  114. except PermissionError as e:
  115. return error_response(403, str(e))
  116. except ValueError as e:
  117. return error_response(404, str(e))
  118. @router.post("/sample-freights")
  119. async def create_sample_freight(
  120. body: SampleFreightCreateBody,
  121. user: dict = Depends(require_admin_or_super_admin),
  122. db: Session = Depends(get_db),
  123. ):
  124. try:
  125. tenant_no = _get_tenant_no(db, user)
  126. user_id = _get_current_user_id(user)
  127. items = [it.model_dump(by_alias=True) for it in (body.items or [])]
  128. data = freight_svc.create_freight(
  129. db,
  130. tenant_no=tenant_no,
  131. user_id=user_id,
  132. transport_mode_raw=body.transport_mode,
  133. freight_amount=body.freight_amount,
  134. items=items,
  135. )
  136. return success_response(data, message="创建成功")
  137. except PermissionError as e:
  138. return error_response(403, str(e))
  139. except ValueError as e:
  140. return error_response(400, str(e))
  141. @router.put("/sample-freights/{freight_id}")
  142. async def update_sample_freight(
  143. freight_id: str,
  144. body: SampleFreightUpdateBody,
  145. user: dict = Depends(require_admin_or_super_admin),
  146. db: Session = Depends(get_db),
  147. ):
  148. try:
  149. tenant_no = _get_tenant_no(db, user)
  150. user_id = _get_current_user_id(user)
  151. data = freight_svc.update_freight(
  152. db,
  153. freight_id,
  154. tenant_no=tenant_no,
  155. user_id=user_id,
  156. transport_mode_raw=body.transport_mode,
  157. freight_amount=body.freight_amount,
  158. )
  159. return success_response(data, message="更新成功")
  160. except PermissionError as e:
  161. return error_response(403, str(e))
  162. except ValueError as e:
  163. msg = str(e)
  164. code = 404 if "不存在" in msg else 400
  165. return error_response(code, msg)
  166. @router.post("/sample-freights/{freight_id}/link")
  167. async def link_sample_freight(
  168. freight_id: str,
  169. body: SampleFreightItemsBody,
  170. user: dict = Depends(require_admin_or_super_admin),
  171. db: Session = Depends(get_db),
  172. ):
  173. try:
  174. tenant_no = _get_tenant_no(db, user)
  175. user_id = _get_current_user_id(user)
  176. items = [it.model_dump(by_alias=True) for it in (body.items or [])]
  177. data = freight_svc.link_samples(
  178. db,
  179. freight_id,
  180. tenant_no=tenant_no,
  181. user_id=user_id,
  182. items=items,
  183. )
  184. return success_response(data, message="关联成功")
  185. except PermissionError as e:
  186. return error_response(403, str(e))
  187. except ValueError as e:
  188. msg = str(e)
  189. code = 404 if "不存在" in msg else 400
  190. return error_response(code, msg)
  191. @router.post("/sample-freights/{freight_id}/unlink")
  192. async def unlink_sample_freight(
  193. freight_id: str,
  194. body: SampleFreightItemsBody,
  195. user: dict = Depends(require_admin_or_super_admin),
  196. db: Session = Depends(get_db),
  197. ):
  198. try:
  199. tenant_no = _get_tenant_no(db, user)
  200. user_id = _get_current_user_id(user)
  201. items = [it.model_dump(by_alias=True) for it in (body.items or [])]
  202. data = freight_svc.unlink_samples(
  203. db,
  204. freight_id,
  205. tenant_no=tenant_no,
  206. user_id=user_id,
  207. items=items,
  208. )
  209. return success_response(data, message="已取消关联")
  210. except PermissionError as e:
  211. return error_response(403, str(e))
  212. except ValueError as e:
  213. msg = str(e)
  214. code = 404 if "不存在" in msg else 400
  215. return error_response(code, msg)