vehicle_urea.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. """车辆尿素 API"""
  2. from datetime import date, datetime
  3. from typing import List, Optional
  4. from pydantic import BaseModel, Field
  5. from fastapi import APIRouter, Depends, HTTPException, Query, status
  6. from sqlalchemy.orm import Session
  7. from app.core.database import get_db
  8. from app.core.db_auth import DbUserContext, get_db_current_user
  9. from app.core.tenant_context import get_tenant_no
  10. from app.utils.excel_export import (
  11. EXPORT_MAX_ROWS,
  12. ExportColumn,
  13. ExportValidationError,
  14. export_rows_to_xlsx_response,
  15. filter_export_columns,
  16. )
  17. from app.schemas.pl.vehicle_urea import (
  18. VehicleUreaApplyCreate,
  19. VehicleUreaApplyListResponse,
  20. VehicleUreaApplyRead,
  21. VehicleUreaApplyUpdate,
  22. VehicleUreaDisburseBoardListResponse,
  23. VehicleUreaDisburseCreate,
  24. VehicleUreaDisburseRead,
  25. VehicleUreaDisburseUpdate,
  26. )
  27. from app.services import pl_vehicle_urea_service as svc
  28. apply_router = APIRouter(prefix="/vehicle-urea-apply", tags=["运输计划-车辆尿素申请"])
  29. disburse_router = APIRouter(prefix="/vehicle-urea-disburse", tags=["运输计划-车辆尿素发放"])
  30. @apply_router.get("/", response_model=VehicleUreaApplyListResponse)
  31. def list_applies(
  32. q: Optional[str] = Query(default=None),
  33. status: Optional[str] = Query(default=None),
  34. apply_date_from: Optional[date] = Query(default=None, alias="applyDateFrom"),
  35. apply_date_to: Optional[date] = Query(default=None, alias="applyDateTo"),
  36. applicant_id: Optional[str] = Query(default=None, alias="applicantId"),
  37. page: int = Query(default=1, ge=1),
  38. page_size: int = Query(default=20, ge=1, le=500, alias="pageSize"),
  39. db: Session = Depends(get_db),
  40. user: DbUserContext = Depends(get_db_current_user),
  41. ) -> VehicleUreaApplyListResponse:
  42. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  43. items, total = svc.list_applies(
  44. db,
  45. tenant_no,
  46. user,
  47. q=q,
  48. status=status,
  49. apply_date_from=apply_date_from,
  50. apply_date_to=apply_date_to,
  51. applicant_id=applicant_id,
  52. page=page,
  53. page_size=page_size,
  54. )
  55. return VehicleUreaApplyListResponse(
  56. items=items, total=total, page=page, pageSize=page_size
  57. )
  58. UREA_APPLY_EXPORT_COLUMNS = [
  59. ExportColumn(title="申请单号", field="applyNo"),
  60. ExportColumn(title="车牌号", field="licensePlate"),
  61. ExportColumn(title="申请时间", field="applyDate"),
  62. ExportColumn(title="入库时间", field="warehouseInDate"),
  63. ExportColumn(title="单位", field="unit"),
  64. ExportColumn(title="入库数量", field="quantity"),
  65. ExportColumn(title="申请人", field="applicantName"),
  66. ExportColumn(title="状态", field="status"),
  67. ]
  68. class UreaApplyExportBody(BaseModel):
  69. q: Optional[str] = None
  70. status: Optional[str] = None
  71. apply_date_from: Optional[date] = Field(default=None, alias="applyDateFrom")
  72. apply_date_to: Optional[date] = Field(default=None, alias="applyDateTo")
  73. ids: Optional[List[str]] = None
  74. columns: Optional[List[str]] = None
  75. model_config = {"populate_by_name": True}
  76. @apply_router.post("/export")
  77. def export_urea_applies(
  78. body: UreaApplyExportBody,
  79. db: Session = Depends(get_db),
  80. user: DbUserContext = Depends(get_db_current_user),
  81. ):
  82. try:
  83. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  84. items, _ = svc.list_applies(
  85. db, tenant_no, user,
  86. q=body.q, status=body.status,
  87. apply_date_from=body.apply_date_from, apply_date_to=body.apply_date_to,
  88. ids=body.ids, page=1, page_size=EXPORT_MAX_ROWS, max_page_size=EXPORT_MAX_ROWS,
  89. )
  90. rows = []
  91. for item in items:
  92. data = item.model_dump(by_alias=True)
  93. for k, v in list(data.items()):
  94. if hasattr(v, 'isoformat'):
  95. data[k] = str(v)[:19]
  96. rows.append(data)
  97. cols = filter_export_columns(UREA_APPLY_EXPORT_COLUMNS, body.columns)
  98. date_str = datetime.now().strftime("%Y%m%d")
  99. return export_rows_to_xlsx_response(
  100. db, tenant_no=tenant_no, sheet_title="尿素申请", columns=cols, rows=rows,
  101. filename_stem=f"尿素申请_{date_str}",
  102. )
  103. except ExportValidationError as e:
  104. raise HTTPException(status_code=400, detail=str(e)) from e
  105. @apply_router.get("/{id}", response_model=VehicleUreaApplyRead)
  106. def get_apply(
  107. id: str,
  108. db: Session = Depends(get_db),
  109. user: DbUserContext = Depends(get_db_current_user),
  110. ) -> VehicleUreaApplyRead:
  111. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  112. return svc.get_apply(db, tenant_no, user, id)
  113. @apply_router.post("/", response_model=VehicleUreaApplyRead, status_code=status.HTTP_201_CREATED)
  114. def create_apply(
  115. payload: VehicleUreaApplyCreate,
  116. db: Session = Depends(get_db),
  117. user: DbUserContext = Depends(get_db_current_user),
  118. ) -> VehicleUreaApplyRead:
  119. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  120. return svc.create_apply(db, tenant_no, user, payload)
  121. @apply_router.put("/{id}", response_model=VehicleUreaApplyRead)
  122. def update_apply(
  123. id: str,
  124. payload: VehicleUreaApplyUpdate,
  125. db: Session = Depends(get_db),
  126. user: DbUserContext = Depends(get_db_current_user),
  127. ) -> VehicleUreaApplyRead:
  128. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  129. return svc.update_apply(db, tenant_no, user, id, payload)
  130. @apply_router.post("/{id}/cancel", response_model=VehicleUreaApplyRead)
  131. def cancel_apply(
  132. id: str,
  133. db: Session = Depends(get_db),
  134. user: DbUserContext = Depends(get_db_current_user),
  135. ) -> VehicleUreaApplyRead:
  136. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  137. return svc.cancel_apply(db, tenant_no, user, id)
  138. @apply_router.delete("/{ids}", status_code=status.HTTP_204_NO_CONTENT)
  139. def delete_applies(
  140. ids: str,
  141. db: Session = Depends(get_db),
  142. user: DbUserContext = Depends(get_db_current_user),
  143. ) -> None:
  144. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  145. apply_ids = [item for item in ids.split(",") if item]
  146. svc.delete_applies(db, tenant_no, user, apply_ids)
  147. @disburse_router.get("/disburse-board", response_model=VehicleUreaDisburseBoardListResponse)
  148. def list_disburse_board(
  149. q: Optional[str] = Query(default=None),
  150. apply_status: Optional[str] = Query(default=None, alias="applyStatus"),
  151. apply_date_from: Optional[date] = Query(default=None, alias="applyDateFrom"),
  152. apply_date_to: Optional[date] = Query(default=None, alias="applyDateTo"),
  153. disburse_date_from: Optional[date] = Query(default=None, alias="disburseDateFrom"),
  154. disburse_date_to: Optional[date] = Query(default=None, alias="disburseDateTo"),
  155. page: int = Query(default=1, ge=1),
  156. page_size: int = Query(default=20, ge=1, le=500, alias="pageSize"),
  157. db: Session = Depends(get_db),
  158. user: DbUserContext = Depends(get_db_current_user),
  159. ) -> VehicleUreaDisburseBoardListResponse:
  160. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  161. items, total = svc.list_disburse_board(
  162. db,
  163. tenant_no,
  164. user,
  165. q=q,
  166. apply_status=apply_status,
  167. apply_date_from=apply_date_from,
  168. apply_date_to=apply_date_to,
  169. disburse_date_from=disburse_date_from,
  170. disburse_date_to=disburse_date_to,
  171. page=page,
  172. page_size=page_size,
  173. )
  174. return VehicleUreaDisburseBoardListResponse(
  175. items=items, total=total, page=page, pageSize=page_size
  176. )
  177. UREA_DISBURSE_EXPORT_COLUMNS = [
  178. ExportColumn(title="申请单号", field="applyNo"),
  179. ExportColumn(title="车牌号", field="licensePlate"),
  180. ExportColumn(title="申请时间", field="applyDate"),
  181. ExportColumn(title="入库时间", field="warehouseInDate"),
  182. ExportColumn(title="申请人", field="applicantName"),
  183. ExportColumn(title="单位", field="unit"),
  184. ExportColumn(title="入库数量", field="quantity"),
  185. ExportColumn(title="申请状态", field="applyStatus"),
  186. ExportColumn(title="发放日期", field="disburseDate"),
  187. ExportColumn(title="发放金额", field="amount"),
  188. ]
  189. class UreaDisburseExportBody(BaseModel):
  190. q: Optional[str] = None
  191. apply_status: Optional[str] = Field(default=None, alias="applyStatus")
  192. apply_date_from: Optional[date] = Field(default=None, alias="applyDateFrom")
  193. apply_date_to: Optional[date] = Field(default=None, alias="applyDateTo")
  194. disburse_date_from: Optional[date] = Field(default=None, alias="disburseDateFrom")
  195. disburse_date_to: Optional[date] = Field(default=None, alias="disburseDateTo")
  196. ids: Optional[List[str]] = None
  197. columns: Optional[List[str]] = None
  198. model_config = {"populate_by_name": True}
  199. @disburse_router.post("/disburse-board/export")
  200. def export_urea_disburse_board(
  201. body: UreaDisburseExportBody,
  202. db: Session = Depends(get_db),
  203. user: DbUserContext = Depends(get_db_current_user),
  204. ):
  205. try:
  206. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  207. items, _ = svc.list_disburse_board(
  208. db, tenant_no, user,
  209. q=body.q, apply_status=body.apply_status,
  210. apply_date_from=body.apply_date_from, apply_date_to=body.apply_date_to,
  211. disburse_date_from=body.disburse_date_from, disburse_date_to=body.disburse_date_to,
  212. ids=body.ids, page=1, page_size=EXPORT_MAX_ROWS, max_page_size=EXPORT_MAX_ROWS,
  213. )
  214. rows = []
  215. for item in items:
  216. data = item.model_dump(by_alias=True)
  217. for k, v in list(data.items()):
  218. if hasattr(v, 'isoformat'):
  219. data[k] = str(v)[:19]
  220. rows.append(data)
  221. cols = filter_export_columns(UREA_DISBURSE_EXPORT_COLUMNS, body.columns)
  222. date_str = datetime.now().strftime("%Y%m%d")
  223. return export_rows_to_xlsx_response(
  224. db, tenant_no=tenant_no, sheet_title="尿素发放", columns=cols, rows=rows,
  225. filename_stem=f"尿素发放_{date_str}",
  226. )
  227. except ExportValidationError as e:
  228. raise HTTPException(status_code=400, detail=str(e)) from e
  229. @disburse_router.get("/{id}", response_model=VehicleUreaDisburseRead)
  230. def get_disburse(
  231. id: str,
  232. db: Session = Depends(get_db),
  233. user: DbUserContext = Depends(get_db_current_user),
  234. ) -> VehicleUreaDisburseRead:
  235. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  236. return svc.get_disburse(db, tenant_no, user, id)
  237. @disburse_router.post("/", response_model=VehicleUreaDisburseRead, status_code=status.HTTP_201_CREATED)
  238. def create_disburse(
  239. payload: VehicleUreaDisburseCreate,
  240. db: Session = Depends(get_db),
  241. user: DbUserContext = Depends(get_db_current_user),
  242. ) -> VehicleUreaDisburseRead:
  243. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  244. return svc.create_disburse(db, tenant_no, user, payload)
  245. @disburse_router.put("/{id}", response_model=VehicleUreaDisburseRead)
  246. def update_disburse(
  247. id: str,
  248. payload: VehicleUreaDisburseUpdate,
  249. db: Session = Depends(get_db),
  250. user: DbUserContext = Depends(get_db_current_user),
  251. ) -> VehicleUreaDisburseRead:
  252. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  253. return svc.update_disburse(db, tenant_no, user, id, payload)
  254. @disburse_router.delete("/{ids}", status_code=status.HTTP_204_NO_CONTENT)
  255. def delete_disburses(
  256. ids: str,
  257. db: Session = Depends(get_db),
  258. user: DbUserContext = Depends(get_db_current_user),
  259. ) -> None:
  260. tenant_no = get_tenant_no(db, user.to_tenant_user_dict())
  261. disburse_ids = [item for item in ids.split(",") if item]
  262. svc.delete_disburses(db, tenant_no, user, disburse_ids)