controller.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. import io
  2. from typing import Annotated, Any, Optional, Dict
  3. from fastapi import APIRouter, Body, Depends, Path, Query
  4. from fastapi.responses import JSONResponse, StreamingResponse
  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 app.core.base_params import PaginationQueryParam
  11. from .schema import (
  12. AccountAuthorizeApplySchema,
  13. AccountAuthorizeApplyOutSchema,
  14. AccountCreateSchema,
  15. AccountDepositSchema,
  16. AccountDepositOutSchema,
  17. AccountOperationOutSchema,
  18. AccountQuerySchema,
  19. AccountTransferSchema,
  20. TransferListOutSchema,
  21. TransferOutSchema,
  22. TransferTaskOutSchema,
  23. ConsumeDetailOutSchema,
  24. )
  25. from .service import AccountService
  26. AccountRouter = APIRouter(
  27. route_class=OperationLogRoute,
  28. prefix="/account",
  29. tags=["资金专户"],
  30. )
  31. @AccountRouter.post(
  32. "/authorize/apply",
  33. summary="申请转账授权签约",
  34. description="申请转账授权签约",
  35. response_model=ResponseSchema[AccountAuthorizeApplyOutSchema],
  36. )
  37. async def authorize_apply_controller(
  38. data: AccountAuthorizeApplySchema,
  39. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:authorize"]))],
  40. ) -> JSONResponse:
  41. """申请转账授权签约"""
  42. result = await AccountService.authorize_apply_service(auth=auth, data=data)
  43. log.info(f"申请转账授权签约成功: {data.enterprise_id}")
  44. return SuccessResponse(data=result, msg="申请转账授权签约成功")
  45. @AccountRouter.post(
  46. "",
  47. summary="开通资金专户",
  48. description="开通资金专户",
  49. response_model=ResponseSchema[AccountOperationOutSchema],
  50. )
  51. async def create_account_controller(
  52. data: AccountCreateSchema,
  53. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:create"]))],
  54. ) -> JSONResponse:
  55. """开通资金专户"""
  56. result = await AccountService.create_account_service(auth=auth, data=data)
  57. log.info(f"开通资金专户成功: {data.enterprise_id}")
  58. return SuccessResponse(data=result, msg="开通资金专户成功")
  59. @AccountRouter.get(
  60. "/query/{enterprise_id}",
  61. summary="查询资金专户",
  62. description="根据企业ID查询资金专户(调用支付宝接口)",
  63. response_model=ResponseSchema[list[Any]],
  64. )
  65. async def query_account_controller(
  66. # data: AccountQuerySchema,
  67. enterprise_id: Annotated[str, Path(description="企业ID")],
  68. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:detail"]))],
  69. ) -> JSONResponse:
  70. """查询资金专户"""
  71. result = await AccountService.query_account_service(auth=auth, data=AccountQuerySchema(enterprise_id=enterprise_id))
  72. log.info(f"查询资金专户成功: {enterprise_id}")
  73. return SuccessResponse(data=result, msg="查询资金专户成功")
  74. @AccountRouter.post(
  75. "/deposit",
  76. summary="资金专户充值",
  77. description="从支付宝余额向资金专户充值",
  78. response_model=ResponseSchema[AccountDepositOutSchema],
  79. )
  80. async def deposit_controller(
  81. data: AccountDepositSchema,
  82. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:deposit"]))],
  83. ) -> JSONResponse:
  84. """资金专户充值"""
  85. result = await AccountService.deposit_service(auth=auth, data=data)
  86. log.info(f"资金专户充值发起成功: {data.enterprise_id} -> {str(data.amount)}")
  87. return SuccessResponse(data=result, msg="充值页面获取成功,请跳转完成支付")
  88. @AccountRouter.post(
  89. "/transfer",
  90. summary="资金专户转账",
  91. description="从资金专户转账到支付宝账户/银行卡/资金专户",
  92. response_model=ResponseSchema[TransferTaskOutSchema],
  93. )
  94. async def transfer_controller(
  95. data: AccountTransferSchema,
  96. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer"]))],
  97. ) -> JSONResponse:
  98. """资金专户转账"""
  99. result = await AccountService.transfer_service(auth=auth, data=data)
  100. log.info(f"资金专户转账发起成功: 企业: {data.enterprise_id}, 金额: {data.amount}")
  101. return SuccessResponse(data=result, msg="转账申请已提交")
  102. # @AccountRouter.post(
  103. # "/withdraw",
  104. # summary="资金专户提现",
  105. # description="从资金专户向支付宝余额提现",
  106. # response_model=ResponseSchema[AccountOperationOutSchema],
  107. # )
  108. # async def withdraw_controller(
  109. # data: AccountWithdrawSchema,
  110. # auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:withdraw"]))],
  111. # ) -> JSONResponse:
  112. # """资金专户提现"""
  113. # result = await AccountService.withdraw_service(auth=auth, data=data)
  114. # log.info(f"资金专户提现发起成功: {data.out_biz_no} -> {data.amount}")
  115. # return SuccessResponse(data=result, msg="提现申请已提交")
  116. @AccountRouter.get(
  117. "/transfer/{out_biz_no}",
  118. summary="查询转账记录详情",
  119. description="根据订单号查询转账记录",
  120. response_model=ResponseSchema[TransferOutSchema],
  121. )
  122. async def transfer_detail_controller(
  123. out_biz_no: Annotated[str, Path(description="商家侧订单号")],
  124. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer:detail"]))],
  125. ) -> JSONResponse:
  126. """查询转账记录详情"""
  127. result = await AccountService.transfer_detail_service(auth=auth, out_biz_no=out_biz_no)
  128. log.info(f"查询转账记录详情成功: {out_biz_no}")
  129. return SuccessResponse(data=result, msg="查询转账记录详情成功")
  130. @AccountRouter.get(
  131. "/transfer",
  132. summary="查询转账记录列表",
  133. description="分页查询转账记录列表",
  134. response_model=ResponseSchema[TransferListOutSchema],
  135. )
  136. async def transfer_list_controller(
  137. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer:list"]))],
  138. page_no: Annotated[int, Query(description="页码")] = 1,
  139. page_size: Annotated[int, Query(description="每页数量")] = 20,
  140. out_biz_no: Annotated[str | None, Query(description="订单号")] = None,
  141. status: Annotated[str | None, Query(description="状态")] = None,
  142. ) -> JSONResponse:
  143. """查询转账记录列表"""
  144. search = {}
  145. if out_biz_no:
  146. search["out_biz_no"] = out_biz_no
  147. if status:
  148. search["status"] = status
  149. result = await AccountService.transfer_list_service(
  150. auth=auth, page_no=page_no, page_size=page_size, search=search
  151. )
  152. return SuccessResponse(data=result, msg="查询转账记录列表成功")
  153. @AccountRouter.get(
  154. "/consume-detail",
  155. summary="账单详情查询",
  156. description="查询企业码账单详情,支持查询关联退款、订单、票据等信息",
  157. response_model=ResponseSchema[ConsumeDetailOutSchema],
  158. )
  159. async def consume_detail_query_controller(
  160. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:consume:detail"]))],
  161. pay_no: Annotated[str, Query(description="支付宝账单号")],
  162. enterprise_id: Annotated[str | None, Query(description="企业ID(2.0接口签约企业必填)")] = None,
  163. ant_shop_id: Annotated[str | None, Query(description="蚂蚁门店ID(商户服务商必填)")] = None,
  164. query_options: Annotated[str | None, Query(description="查询选项,多个用逗号分隔")] = None,
  165. ) -> JSONResponse:
  166. """
  167. 账单详情查询
  168. 调用: alipay.commerce.ec.consume.detail.query
  169. 用于查询企业码账单详情,支持查询关联退款、订单、票据等信息。
  170. - pay_no: 支付宝账单号(必填)
  171. - enterprise_id: 企业ID(2.0接口签约企业必填)
  172. - ant_shop_id: 蚂蚁门店ID(商户服务商必填)
  173. - query_options: 查询选项,支持 Refund/Order/Ticket,多个用逗号分隔
  174. """
  175. options_list = None
  176. if query_options:
  177. options_list = [opt.strip() for opt in query_options.split(",") if opt.strip()]
  178. result = await AccountService.consume_detail_query_service(
  179. auth=auth,
  180. pay_no=pay_no,
  181. enterprise_id=enterprise_id,
  182. ant_shop_id=ant_shop_id,
  183. query_options=options_list,
  184. )
  185. log.info(f"账单详情查询成功: {pay_no}")
  186. return SuccessResponse(data=result, msg="账单详情查询成功")
  187. @AccountRouter.get(
  188. "/transfer/export",
  189. summary="导出转账记录报表",
  190. description="导出指定时间范围内的转账记录为Excel文件",
  191. responses={
  192. 200: {
  193. "description": "Excel文件下载",
  194. "content": {
  195. "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": {}
  196. }
  197. }
  198. },
  199. )
  200. async def transfer_export_controller(
  201. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer:list"]))],
  202. start_time: Annotated[str, Query(description="开始时间,格式:YYYY-MM-DD HH:MM:SS")],
  203. end_time: Annotated[str, Query(description="结束时间,格式:YYYY-MM-DD HH:MM:SS")],
  204. enterprise_id: Annotated[str | None, Query(description="企业ID(2.0接口签约企业必填)")] = None,
  205. ) -> StreamingResponse:
  206. """导出转账记录报表"""
  207. result = await AccountService.transfer_export_service(
  208. auth=auth, start_time=start_time, end_time=end_time, enterprise_id=enterprise_id
  209. )
  210. log.info(f"导出转账记录报表成功: {start_time} -> {end_time}")
  211. return StreamingResponse(
  212. io.BytesIO(result),
  213. media_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  214. headers={
  215. "Content-Disposition": f"attachment; filename=transfer_report_{start_time}_{end_time}.xlsx"
  216. }
  217. )
  218. # @AccountRouter.post(
  219. # "/receipt/apply",
  220. # summary="申请资金回单",
  221. # description="申请资金业务回单",
  222. # response_model=ResponseSchema[ReceiptApplyOutSchema],
  223. # )
  224. # async def receipt_apply_controller(
  225. # data: ReceiptApplySchema,
  226. # auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:receipt"]))],
  227. # ) -> JSONResponse:
  228. # """申请资金回单"""
  229. # result = await AccountService.receipt_apply_service(auth=auth, data=data)
  230. # log.info(f"申请资金回单成功: {data.order_no}")
  231. # return SuccessResponse(data=result, msg="申请资金回单成功")
  232. # @AccountRouter.get(
  233. # "/receipt/{file_id}",
  234. # summary="查询资金回单",
  235. # description="查询资金业务回单状态",
  236. # response_model=ResponseSchema[ReceiptQueryOutSchema],
  237. # )
  238. # async def receipt_query_controller(
  239. # file_id: Annotated[str, Path(description="文件申请号")],
  240. # auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:receipt"]))],
  241. # enterprise_id: Annotated[str, Query(description="企业ID")] = None,
  242. # ) -> JSONResponse:
  243. # """查询资金回单"""
  244. # if not enterprise_id:
  245. # enterprise_id = auth.enterprise_id or ""
  246. # result = await AccountService.receipt_query_service(
  247. # auth=auth, enterprise_id=enterprise_id, file_id=file_id
  248. # )
  249. # log.info(f"查询资金回单成功: {file_id}")
  250. # return SuccessResponse(data=result, msg="查询资金回单成功")
  251. # @AccountRouter.post(
  252. # "/transfer/batch",
  253. # summary="批量资金专户转账",
  254. # description="异步批量转账,先放入队列,后台处理",
  255. # response_model=ResponseSchema[AccountTransferBatchOutSchema],
  256. # )
  257. # async def batch_transfer_controller(
  258. # data: AccountTransferBatchSchema,
  259. # auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer"]))],
  260. # ) -> JSONResponse:
  261. # """批量资金专户转账(异步)"""
  262. # result = await AccountService.batch_transfer_service(auth=auth, data=data)
  263. # log.info(f"批量转账任务已提交: {result.batch_id}, 总笔数: {result.total}")
  264. # return SuccessResponse(data=result, msg="批量转账任务已提交,正在处理中")
  265. # @AccountRouter.get(
  266. # "/transfer/batch/{batch_id}",
  267. # summary="查询批量转账结果",
  268. # description="查询批量转账的处理状态和结果",
  269. # response_model=ResponseSchema[dict],
  270. # )
  271. # async def get_batch_result_controller(
  272. # batch_id: Annotated[str, Path(description="批次ID")],
  273. # auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:account:transfer"]))],
  274. # ) -> JSONResponse:
  275. # """查询批量转账结果"""
  276. # result = await AccountService.get_batch_result_service(auth=auth, batch_id=batch_id)
  277. # log.info(f"查询批量转账结果成功: {batch_id}")
  278. # return SuccessResponse(data=result, msg="查询批量转账结果成功")