controller.py 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335
  1. from typing import Annotated
  2. import uuid
  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 app.plugin.module_payment.expense.institution.schema import InstitutionListOutSchema
  11. from .service import InstitutionService, InstitutionScopeService, IssueruleService
  12. from alipay.aop.api.domain.AlipayEbppInvoiceInstitutionCreateModel import (
  13. AlipayEbppInvoiceInstitutionCreateModel,
  14. )
  15. from alipay.aop.api.response.AlipayEbppInvoiceInstitutionCreateResponse import (
  16. AlipayEbppInvoiceInstitutionCreateResponse,
  17. )
  18. from alipay.aop.api.domain.AlipayEbppInvoiceInstitutionDeleteModel import (
  19. AlipayEbppInvoiceInstitutionDeleteModel,
  20. )
  21. from alipay.aop.api.response.AlipayEbppInvoiceInstitutionDeleteResponse import (
  22. AlipayEbppInvoiceInstitutionDeleteResponse,
  23. )
  24. from alipay.aop.api.domain.AlipayEbppInvoiceInstitutionModifyModel import (
  25. AlipayEbppInvoiceInstitutionModifyModel,
  26. )
  27. from alipay.aop.api.response.AlipayEbppInvoiceInstitutionModifyResponse import (
  28. AlipayEbppInvoiceInstitutionModifyResponse,
  29. )
  30. InstitutionRouter = APIRouter(
  31. route_class=OperationLogRoute,
  32. prefix="/institution",
  33. tags=["费控制度"],
  34. )
  35. @InstitutionRouter.post(
  36. "",
  37. summary="创建费控制度",
  38. description="创建费控制度。支持串联调用:创建制度→设置成员→创建发放规则",
  39. )
  40. async def create_institution_controller(
  41. data: dict,
  42. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:create"]))],
  43. ) -> JSONResponse:
  44. """创建费控制度(含完整串联流程)"""
  45. enterprise_id = data.get("enterprise_id", "")
  46. if not enterprise_id:
  47. from app.plugin.module_payment.enterprise.model import EnterpriseModel
  48. from sqlalchemy import select
  49. stmt = select(EnterpriseModel).where(EnterpriseModel.tenant_id == auth.tenant_id).limit(1)
  50. result = await auth.db.execute(stmt)
  51. enterprise = result.scalar_one_or_none()
  52. enterprise_id = enterprise.enterprise_id if enterprise else ""
  53. if enterprise_id:
  54. data["enterprise_id"] = enterprise_id
  55. institution_create_model = AlipayEbppInvoiceInstitutionCreateModel.from_alipay_dict(data)
  56. # 解析适用成员数据
  57. scope_data = None
  58. adapter_type = data.get("applicable_scope")
  59. if adapter_type and adapter_type != "NONE":
  60. scope_data = {
  61. "adapter_type": adapter_type,
  62. "owner_type": data.get("scope_owner_type", "EMPLOYEE"),
  63. "add_owner_id_list": data.get("scope_owner_id_list"),
  64. }
  65. # 解析发放规则数据
  66. issuerule_data = None
  67. if data.get("grant_mode") == "period":
  68. period_type_raw = data.get("period_type", "monthly")
  69. # 映射前端period_type到支付宝枚举
  70. ISSUE_TYPE_MAP = {
  71. "daily": "ISSUE_DAY",
  72. "weekly": "ISSUE_WEEK",
  73. "monthly": "ISSUE_MONTH",
  74. "quarterly": "ISSUE_QUARTER",
  75. "yearly": "ISSUE_YEAR",
  76. }
  77. issue_type = ISSUE_TYPE_MAP.get(period_type_raw, "ISSUE_MONTH")
  78. amount = data.get("amount", 0)
  79. # 有效时间配置
  80. effective_time_type = data.get("effective_time_type", "unlimited")
  81. if effective_time_type == "unlimited":
  82. effective_period = '{"all": true}'
  83. elif effective_time_type == "workday":
  84. workday_start = data.get("workday_start_time", "00:00")
  85. workday_end = data.get("workday_end_time", "23:59")
  86. effective_period = f'{{"regular":{{"workday":[["{workday_start}","{workday_end}"]]}}}}'
  87. else:
  88. effective_period = '{"all": true}'
  89. issuerule_data = {
  90. "quota_type": "CAP",
  91. "issue_type": issue_type,
  92. "issue_amount_value": str(amount),
  93. "issue_rule_name": data.get("name", "") + "-发放规则",
  94. "effective_period": effective_period,
  95. "invalid_mode": 1 if data.get("effective_time_type") == "unlimited" else 0,
  96. "share_mode": 0,
  97. "outer_source_id": data.get("outer_source_id") or str(uuid.uuid4()),
  98. }
  99. result = await InstitutionService.create_institution_full_flow(
  100. auth=auth,
  101. institution_model=institution_create_model,
  102. enterprise_id=enterprise_id,
  103. scope_data=scope_data,
  104. issuerule_data=issuerule_data,
  105. )
  106. log.info(f"创建费控制度成功: institution_id={result.get('institution_id')}")
  107. return SuccessResponse(data=result, msg="创建费控制度成功")
  108. @InstitutionRouter.get(
  109. "",
  110. summary="查询费控制度列表",
  111. description="分页查询费控制度列表",
  112. response_model=ResponseSchema[InstitutionListOutSchema],
  113. )
  114. async def list_institution_controller(
  115. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:list"]))],
  116. page_no: Annotated[int, Query(description="页码")] = 1,
  117. page_size: Annotated[int, Query(description="每页数量")] = 20,
  118. enterprise_id: Annotated[str | None, Query(description="企业ID")] = None,
  119. name: Annotated[str | None, Query(description="制度名称")] = None,
  120. expense_type: Annotated[str | None, Query(description="费用类型")] = None,
  121. status: Annotated[str | None, Query(description="状态")] = None,
  122. ) -> JSONResponse:
  123. """查询费控制度列表"""
  124. search = {}
  125. if enterprise_id:
  126. search["enterprise_id"] = enterprise_id
  127. if name:
  128. search["name"] = name
  129. if expense_type:
  130. search["expense_type"] = expense_type
  131. if status:
  132. search["status"] = status
  133. result = await InstitutionService.list_service(
  134. auth=auth, page_no=page_no, page_size=page_size, search=search
  135. )
  136. return SuccessResponse(data=result, msg="查询费控制度列表成功")
  137. @InstitutionRouter.get(
  138. "/{institution_id}",
  139. summary="查询费控制度详情",
  140. description="查询费控制度详情 (alipay.ebpp.invoice.institution.detailinfo.query),失败时降级到本地DB",
  141. )
  142. async def detail_institution_controller(
  143. institution_id: Annotated[str, Path(description="制度ID")],
  144. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:detail"]))],
  145. enterprise_id: Annotated[str | None, Query(description="企业ID")] = None,
  146. ) -> JSONResponse:
  147. """查询费控制度详情"""
  148. if not enterprise_id:
  149. return SuccessResponse(data=None, msg="企业ID不能为空")
  150. result = await InstitutionService.detailinfo_query_service(
  151. auth=auth,
  152. institution_id=institution_id,
  153. enterprise_id=enterprise_id,
  154. )
  155. if result is None:
  156. return SuccessResponse(data=None, msg="制度不存在")
  157. return SuccessResponse(data=result, msg="查询费控制度详情成功")
  158. @InstitutionRouter.delete(
  159. "",
  160. summary="删除费控制度",
  161. description="删除费控制度 (alipay.ebpp.invoice.institution.delete)",
  162. )
  163. async def delete_institution_controller(
  164. data: dict,
  165. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:delete"]))],
  166. ) -> JSONResponse:
  167. """删除费控制度"""
  168. institution_delete_model = AlipayEbppInvoiceInstitutionDeleteModel(**data)
  169. result = await InstitutionService.delete_institution_service(auth=auth, data=institution_delete_model)
  170. log.info(f"删除费控制度成功: institution_id={institution_delete_model.institution_id}, enterprise_id={institution_delete_model.enterprise_id}")
  171. return SuccessResponse(data=result, msg="删除费控制度成功")
  172. @InstitutionRouter.post(
  173. "/modify",
  174. summary="编辑费控制度",
  175. description="编辑费控制度 (alipay.ebpp.invoice.institution.modify)",
  176. )
  177. async def modify_institution_controller(
  178. data: dict,
  179. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:modify"]))],
  180. ) -> JSONResponse:
  181. """编辑费控制度"""
  182. institution_modify_model = AlipayEbppInvoiceInstitutionModifyModel(**data)
  183. result = await InstitutionService.modify_institution_service(auth=auth, data=institution_modify_model)
  184. log.info(f"编辑费控制度成功: institution_id={institution_modify_model.institution_id}")
  185. return SuccessResponse(data=result, msg="编辑费控制度成功")
  186. # ========== 制度成员范围管理 ==========
  187. @InstitutionRouter.get(
  188. "/{institution_id}/scope",
  189. summary="查询制度成员范围",
  190. description="查询制度下成员范围 (alipay.ebpp.invoice.institution.scopepageinfo.query)",
  191. )
  192. async def list_scope_controller(
  193. institution_id: Annotated[str, Path(description="制度ID")],
  194. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:scope:list"]))],
  195. enterprise_id: Annotated[str | None, Query(description="企业ID")] = None,
  196. owner_type: Annotated[str | None, Query(description="适配ID类型")] = None,
  197. page_num: Annotated[int, Query(description="页码")] = 1,
  198. page_size: Annotated[int, Query(description="每页条数")] = 20,
  199. ) -> JSONResponse:
  200. """查询制度成员"""
  201. result = await InstitutionScopeService.scopepageinfo_query_service(
  202. auth=auth,
  203. institution_id=institution_id,
  204. enterprise_id=enterprise_id,
  205. page_num=page_num,
  206. page_size=page_size,
  207. owner_type=owner_type,
  208. )
  209. return SuccessResponse(data=result, msg="查询成功")
  210. @InstitutionRouter.post(
  211. "/{institution_id}/scope",
  212. summary="设置制度成员范围",
  213. description="设置/修改制度成员范围 (alipay.ebpp.invoice.institution.scope.modify)",
  214. )
  215. async def modify_scope_controller(
  216. institution_id: Annotated[str, Path(description="制度ID")],
  217. data: dict,
  218. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:scope:modify"]))],
  219. ) -> JSONResponse:
  220. """设置制度成员"""
  221. result = await InstitutionScopeService.scope_modify_service(
  222. auth=auth,
  223. institution_id=institution_id,
  224. data=data,
  225. )
  226. log.info(f"设置制度成员成功: institution_id={institution_id}, adapter_type={data.get('adapter_type')}")
  227. return SuccessResponse(data=result, msg="设置成功")
  228. # ========== 自动额度发放规则管理 ==========
  229. @InstitutionRouter.post(
  230. "/{institution_id}/issuerule",
  231. summary="创建自动发放规则",
  232. description="创建自动额度发放规则 (alipay.ebpp.invoice.issuerule.create)",
  233. )
  234. async def create_issuerule_controller(
  235. institution_id: Annotated[str, Path(description="制度ID")],
  236. data: dict,
  237. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:issuerule:create"]))],
  238. ) -> JSONResponse:
  239. """创建自动发放规则"""
  240. result = await IssueruleService.create_issuerule_service(
  241. auth=auth,
  242. institution_id=institution_id,
  243. enterprise_id=data.get("enterprise_id", ""),
  244. quota_type=data.get("quota_type", "CAP"),
  245. issue_type=data.get("issue_type", "ISSUE_MONTH"),
  246. issue_amount_value=data.get("issue_amount_value", "0"),
  247. outer_source_id=data.get("outer_source_id"),
  248. issue_rule_name=data.get("issue_rule_name"),
  249. effective_period=data.get("effective_period"),
  250. invalid_mode=data.get("invalid_mode"),
  251. share_mode=data.get("share_mode"),
  252. )
  253. log.info(f"创建自动发放规则成功: institution_id={institution_id}")
  254. return SuccessResponse(data=result, msg="创建自动发放规则成功")
  255. @InstitutionRouter.put(
  256. "/{institution_id}/issuerule/{issue_rule_id}",
  257. summary="编辑自动发放规则",
  258. description="编辑自动额度发放规则 (alipay.ebpp.invoice.issuerule.modify)",
  259. )
  260. async def modify_issuerule_controller(
  261. institution_id: Annotated[str, Path(description="制度ID")],
  262. issue_rule_id: Annotated[str, Path(description="发放规则ID")],
  263. data: dict,
  264. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:issuerule:modify"]))],
  265. ) -> JSONResponse:
  266. result = await IssueruleService.modify_issuerule_service(
  267. auth=auth,
  268. institution_id=institution_id,
  269. issue_rule_id=issue_rule_id,
  270. enterprise_id=data.get("enterprise_id", ""),
  271. quota_type=data.get("quota_type"),
  272. issue_type=data.get("issue_type"),
  273. issue_amount_value=data.get("issue_amount_value"),
  274. issue_rule_name=data.get("issue_rule_name"),
  275. effective=data.get("effective"),
  276. effective_period=data.get("effective_period"),
  277. invalid_mode=data.get("invalid_mode"),
  278. share_mode=data.get("share_mode"),
  279. )
  280. log.info(f"编辑自动发放规则成功: issue_rule_id={issue_rule_id}")
  281. return SuccessResponse(data=result, msg="编辑自动发放规则成功")
  282. @InstitutionRouter.delete(
  283. "/{institution_id}/issuerule",
  284. summary="删除自动发放规则",
  285. description="删除自动额度发放规则 (alipay.ebpp.invoice.issuerule.delete)",
  286. )
  287. async def delete_issuerule_controller(
  288. institution_id: Annotated[str, Path(description="制度ID")],
  289. data: dict,
  290. auth: Annotated[AuthSchema, Depends(AuthPermission(["module_payment:expense:institution:issuerule:delete"]))],
  291. ) -> JSONResponse:
  292. result = await IssueruleService.delete_issuerule_service(
  293. auth=auth,
  294. institution_id=institution_id,
  295. issue_rule_id_list=data.get("issue_rule_id_list", []),
  296. enterprise_id=data.get("enterprise_id", ""),
  297. )
  298. log.info(f"删除自动发放规则成功: institution_id={institution_id}")
  299. return SuccessResponse(data=result, msg="删除自动发放规则成功")