controller.py 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163
  1. from typing import Annotated
  2. from apscheduler.schedulers.asyncio import AsyncIOScheduler
  3. from fastapi import APIRouter, Depends, Path, Query
  4. from fastapi.responses import JSONResponse
  5. from app.api.v1.module_system.auth.schema import AuthSchema
  6. from app.common.response import ResponseSchema, SuccessResponse
  7. from app.core.dependencies import AuthPermission
  8. from app.core.logger import log
  9. from app.core.router_class import OperationLogRoute
  10. from .schema import (
  11. FacetofaceApplySchema,
  12. FacetofaceOrderListOutSchema,
  13. FacetofaceOrderOutSchema,
  14. )
  15. from .service import FacetofaceService
  16. FacetofaceRouter = APIRouter(
  17. route_class=OperationLogRoute,
  18. prefix="/facetoface",
  19. tags=["当面付开通"],
  20. )
  21. @FacetofaceRouter.post(
  22. "/apply",
  23. summary="提交当面付开通申请",
  24. description="代商家提交当面付开通申请(自动完成 create → sign → confirm 三步)",
  25. response_model=ResponseSchema[FacetofaceOrderOutSchema],
  26. )
  27. async def apply_controller(
  28. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:facetoface:apply"]))],
  29. data: FacetofaceApplySchema,
  30. ) -> JSONResponse:
  31. result = await FacetofaceService.apply_service(auth=auth, data=data)
  32. log.info(f"当面付开通申请已提交: batch_no={result.batch_no}, merchant={data.merchant_name}")
  33. return SuccessResponse(data=result, msg="当面付开通申请已提交")
  34. @FacetofaceRouter.get(
  35. "",
  36. summary="查询申请单列表",
  37. description="分页查询当面付开通申请单列表",
  38. response_model=ResponseSchema[FacetofaceOrderListOutSchema],
  39. )
  40. async def list_controller(
  41. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:facetoface:list"]))],
  42. page_no: Annotated[int, Query(description="页码")] = 1,
  43. page_size: Annotated[int, Query(description="每页数量")] = 20,
  44. merchant_name: Annotated[str | None, Query(description="商户名称")] = None,
  45. shop_name: Annotated[str | None, Query(description="店铺名称")] = None,
  46. order_status: Annotated[str | None, Query(description="申请单状态")] = None,
  47. start_time: Annotated[str | None, Query(description="开始时间")] = None,
  48. end_time: Annotated[str | None, Query(description="结束时间")] = None,
  49. ) -> JSONResponse:
  50. search = {}
  51. if merchant_name:
  52. search["merchant_name"] = merchant_name
  53. if shop_name:
  54. search["shop_name"] = shop_name
  55. if order_status:
  56. search["order_status"] = order_status
  57. if start_time:
  58. search["start_time"] = start_time
  59. if end_time:
  60. search["end_time"] = end_time
  61. result = await FacetofaceService.list_service(
  62. auth=auth, page_no=page_no, page_size=page_size, search=search
  63. )
  64. return SuccessResponse(data=result, msg="查询成功")
  65. @FacetofaceRouter.get(
  66. "/enterprises/status",
  67. summary="批量查询企业当面付状态",
  68. description="传入企业ID列表,返回各企业的当面付申请状态",
  69. )
  70. async def batch_status_controller(
  71. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:enterprise:list"]))],
  72. ids: Annotated[str, Query(description="企业ID列表,逗号分隔")],
  73. ) -> JSONResponse:
  74. enterprise_ids = [eid.strip() for eid in ids.split(",") if eid.strip()]
  75. result = await FacetofaceService.batch_status_service(auth=auth, enterprise_ids=enterprise_ids)
  76. return SuccessResponse(data=result, msg="查询成功")
  77. @FacetofaceRouter.get(
  78. "/enterprise/{enterprise_id}",
  79. summary="按企业ID查询当面付申请单",
  80. description="查询某个企业的当面付开通申请单",
  81. response_model=ResponseSchema[FacetofaceOrderOutSchema],
  82. )
  83. async def get_by_enterprise_controller(
  84. enterprise_id: Annotated[str, Path(description="企业ID")],
  85. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:facetoface:list"]))],
  86. ) -> JSONResponse:
  87. result = await FacetofaceService.get_by_enterprise_service(auth=auth, enterprise_id=enterprise_id)
  88. return SuccessResponse(data=result, msg="查询成功")
  89. @FacetofaceRouter.get(
  90. "/{order_id}",
  91. summary="查询申请单详情",
  92. description="查询单个当面付开通申请单详情",
  93. response_model=ResponseSchema[FacetofaceOrderOutSchema],
  94. )
  95. async def detail_controller(
  96. order_id: Annotated[int, Path(description="申请单ID")],
  97. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:facetoface:list"]))],
  98. ) -> JSONResponse:
  99. result = await FacetofaceService.detail_service(auth=auth, order_id=order_id)
  100. return SuccessResponse(data=result, msg="查询成功")
  101. @FacetofaceRouter.post(
  102. "/{order_id}/query",
  103. summary="手动查询申请单状态",
  104. description="手动触发查询支付宝申请单最新状态",
  105. response_model=ResponseSchema[FacetofaceOrderOutSchema],
  106. )
  107. async def query_status_controller(
  108. order_id: Annotated[int, Path(description="申请单ID")],
  109. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:facetoface:query"]))],
  110. ) -> JSONResponse:
  111. result = await FacetofaceService.query_order_service(auth=auth, order_id=order_id)
  112. log.info(f"手动查询当面付申请单状态: id={order_id}, status={result.order_status}")
  113. return SuccessResponse(data=result, msg="查询成功")
  114. # ---------- 定时轮询任务 ----------
  115. _poll_scheduler = AsyncIOScheduler()
  116. _poll_scheduler_started = False
  117. @FacetofaceRouter.on_event("startup")
  118. async def start_facetoface_poll_scheduler():
  119. """启动时注册当面付申请单状态轮询任务"""
  120. global _poll_scheduler_started
  121. if _poll_scheduler_started:
  122. return
  123. _poll_scheduler_started = True
  124. _poll_scheduler.add_job(
  125. FacetofaceService.poll_pending_orders,
  126. "interval",
  127. minutes=30,
  128. max_instances=1,
  129. id="facetoface_poll_orders",
  130. replace_existing=True,
  131. )
  132. _poll_scheduler.start()
  133. log.info("[当面付] 状态轮询定时任务已注册(每30分钟执行)")
  134. @FacetofaceRouter.on_event("shutdown")
  135. async def stop_facetoface_poll_scheduler():
  136. if _poll_scheduler.running:
  137. _poll_scheduler.shutdown(wait=False)
  138. log.info("[当面付] 状态轮询定时任务已停止")