service.py 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. from typing import Optional, cast
  2. from app.api.v1.module_system.auth.schema import AuthSchema
  3. from app.api.v1.module_system.user.crud import UserCRUD
  4. from app.api.v1.module_system.user.schema import UserCreateSchema
  5. from app.core.alipay import AlipayClient
  6. from app.core.exceptions import CustomException
  7. from app.core.logger import log
  8. from app.utils.hash_bcrpy_util import PwdUtil
  9. from .crud import EmployeeCRUD
  10. from .schema import (
  11. EmployeeCreateOrUpdateSchema,
  12. EmployeeListOutSchema,
  13. EmployeeOperationOutSchema,
  14. EmployeeInviteQuerySchema,
  15. EmployeeInviteQueryOutSchema,
  16. EmployeeOutSchema,
  17. )
  18. from alipay.aop.api.domain.EmployeeInfoDTO import EmployeeInfoDTO
  19. class EmployeeService:
  20. """员工服务层"""
  21. @classmethod
  22. async def add_employee_service(
  23. cls, auth: AuthSchema, data: EmployeeCreateOrUpdateSchema
  24. ) -> EmployeeOperationOutSchema:
  25. """
  26. 添加员工
  27. 调用: alipay.commerce.ec.employee.add
  28. """
  29. crud = EmployeeCRUD(auth)
  30. from alipay.aop.api.request.AlipayCommerceEcEmployeeAddRequest import (
  31. AlipayCommerceEcEmployeeAddRequest,
  32. )
  33. from alipay.aop.api.domain.AlipayCommerceEcEmployeeAddModel import (
  34. AlipayCommerceEcEmployeeAddModel,
  35. )
  36. from alipay.aop.api.response.AlipayCommerceEcEmployeeAddResponse import (
  37. AlipayCommerceEcEmployeeAddResponse,
  38. )
  39. model = AlipayCommerceEcEmployeeAddModel()
  40. # 必选
  41. model.enterprise_id = data.enterprise_id
  42. model.employee_name = data.employee_name
  43. # 身份标识(identity_type+identity)、身份证(employee_cert_type+employee_cert_no)、
  44. # 手机号、邮箱四者必选其一; 当传入多个时,优先级为:身份标识>身份证>手机号>邮箱
  45. model.identity_type = data.identity_type
  46. model.identity = data.identity
  47. model.identity_open_id = data.identity_open_id
  48. model.employee_mobile = data.employee_mobile
  49. model.employee_email = data.employee_email
  50. model.employee_cert_type = data.employee_cert_type
  51. model.employee_cert_no = data.employee_cert_no
  52. model.iot_check_type = data.iot_check_type
  53. model.employee_no = data.employee_no
  54. model.department_ids = data.department_ids
  55. model.accounting_entity_ids = data.accounting_entity_ids
  56. model.label_names = data.label_names
  57. model.sign_return_url = data.sign_return_url
  58. model.create_share_code = data.create_share_code
  59. model.sign_url_carry_info = data.sign_url_carry_info
  60. model.profiles = data.profiles
  61. request = AlipayCommerceEcEmployeeAddRequest()
  62. request.biz_model = model
  63. client = AlipayClient.get_client()
  64. response = client.execute(request)
  65. if not response:
  66. raise CustomException(msg="添加员工失败: 无响应")
  67. result = AlipayCommerceEcEmployeeAddResponse()
  68. result.parse_response_content(response)
  69. if not result.is_success():
  70. log.error(f"支付宝接口调用失败: {result.code} - {result.msg}")
  71. raise CustomException(msg=f"添加员工失败: {result.sub_msg or result.msg or result.code}")
  72. result_data = EmployeeOperationOutSchema(
  73. employee_id=result.employee_id,
  74. sign_url=result.sign_url,
  75. share_code=result.share_code,
  76. iot_unique_id=result.iot_unique_id,
  77. )
  78. create_data_dict = result_data.model_dump()
  79. create_data_dict.update(data.model_dump())
  80. # 自动创建系统用户记录
  81. user_crud = UserCRUD(auth)
  82. # 检查用户是否已存在
  83. username = str(result.employee_id)
  84. existing_user = await user_crud.get_by_username_crud(username=username)
  85. if not existing_user:
  86. # 创建新用户
  87. user_data = UserCreateSchema(
  88. username=username,
  89. password=PwdUtil.set_password_hash(password="123456"), # 默认密码
  90. name=data.employee_name,
  91. mobile=data.employee_mobile,
  92. email=data.employee_email,
  93. tenant_id=auth.tenant_id,
  94. # role_ids=[11],
  95. # status="0", # 启用状态
  96. description=f"e:{data.enterprise_id}:{result.employee_id}"
  97. )
  98. user_dict = user_data.model_dump(exclude_unset=True)
  99. new_user = await user_crud.create(data=user_dict, skip_tenant_id=True)
  100. create_data_dict["user_id"] = new_user.id
  101. else:
  102. create_data_dict["user_id"] = existing_user.id
  103. await crud.create(data=create_data_dict)
  104. return result_data
  105. @classmethod
  106. async def list_service(
  107. cls,
  108. auth: AuthSchema,
  109. page_no: int = 1,
  110. page_size: int = 20,
  111. search: dict | None = None,
  112. ) -> dict:
  113. """
  114. 查询员工列表
  115. """
  116. crud = EmployeeCRUD(auth)
  117. offset = (page_no - 1) * page_size
  118. return await crud.page(
  119. offset=offset,
  120. limit=page_size,
  121. order_by=[{"id": "desc"}],
  122. search=search or {},
  123. out_schema=EmployeeListOutSchema,
  124. preload=["user"]
  125. )
  126. @classmethod
  127. async def info_service(
  128. cls, auth: AuthSchema, employee_id: Optional[str], employee_email: Optional[str], employee_mobile: Optional[str], enterprise_id: str
  129. ) -> EmployeeOutSchema:
  130. crud = EmployeeCRUD(auth)
  131. out_data = await crud.get(employee_id=employee_id, employee_email=employee_email, employee_mobile=employee_mobile, enterprise_id=enterprise_id)
  132. if not out_data:
  133. raise CustomException(msg="员工不存在")
  134. return EmployeeOutSchema.model_validate(out_data)
  135. @classmethod
  136. async def detail_service(
  137. cls, auth: AuthSchema, employee_id: Optional[str], employee_email: Optional[str], employee_mobile: Optional[str], enterprise_id: str
  138. ) -> dict:
  139. """
  140. 查询员工详情
  141. 调用: alipay.commerce.ec.employee.info.query
  142. """
  143. from alipay.aop.api.request.AlipayCommerceEcEmployeeInfoQueryRequest import AlipayCommerceEcEmployeeInfoQueryRequest
  144. from alipay.aop.api.domain.AlipayCommerceEcEmployeeInfoQueryModel import AlipayCommerceEcEmployeeInfoQueryModel
  145. from alipay.aop.api.response.AlipayCommerceEcEmployeeInfoQueryResponse import AlipayCommerceEcEmployeeInfoQueryResponse
  146. model = AlipayCommerceEcEmployeeInfoQueryModel()
  147. model.enterprise_id = enterprise_id
  148. model.employee_id = employee_id
  149. model.employee_email = employee_email
  150. model.mobile = employee_mobile
  151. request = AlipayCommerceEcEmployeeInfoQueryRequest()
  152. request.biz_model = model
  153. client = AlipayClient.get_client()
  154. response = client.execute(request)
  155. if not response:
  156. raise CustomException(msg="查询员工详情失败: 无响应")
  157. result = AlipayCommerceEcEmployeeInfoQueryResponse()
  158. result.parse_response_content(response)
  159. if not result.is_success():
  160. log.error(f"支付宝接口调用失败: {result.code} - {result.msg}")
  161. raise CustomException(msg=f"查询员工详情失败: {result.msg}")
  162. return EmployeeInfoDTO.to_alipay_dict(cast(EmployeeInfoDTO, result.employee_info))
  163. @classmethod
  164. async def delete_employee_service(
  165. cls, auth: AuthSchema, employee_id: str, enterprise_id: str
  166. ) -> EmployeeOperationOutSchema:
  167. """
  168. 删除员工
  169. 调用: alipay.commerce.ec.employee.delete
  170. """
  171. from alipay.aop.api.request.AlipayCommerceEcEmployeeDeleteRequest import AlipayCommerceEcEmployeeDeleteRequest
  172. from alipay.aop.api.domain.AlipayCommerceEcEmployeeDeleteModel import AlipayCommerceEcEmployeeDeleteModel
  173. from alipay.aop.api.response.AlipayCommerceEcEmployeeDeleteResponse import AlipayCommerceEcEmployeeDeleteResponse
  174. model = AlipayCommerceEcEmployeeDeleteModel()
  175. model.enterprise_id = enterprise_id
  176. model.employee_id = employee_id
  177. request = AlipayCommerceEcEmployeeDeleteRequest()
  178. request.biz_model = model
  179. client = AlipayClient.get_client()
  180. response = client.execute(request)
  181. if not response:
  182. raise CustomException(msg="删除员工失败: 无响应")
  183. result = AlipayCommerceEcEmployeeDeleteResponse()
  184. result.parse_response_content(response)
  185. if not result.is_success():
  186. log.error(f"支付宝接口调用失败: {result.code} - {result.msg}")
  187. raise CustomException(msg=f"删除员工失败: {result.sub_msg or result.msg or result.code}")
  188. # 从本地数据库删除, 并删除关联的用户
  189. # 先查询员工是否存在
  190. crud = EmployeeCRUD(auth)
  191. employee = await crud.get(employee_id=employee_id, enterprise_id=enterprise_id, preload=["user"])
  192. if not employee:
  193. raise CustomException(msg=f"员工 {employee_id} 不存在")
  194. # 先删除关联的用户
  195. if employee.user_id:
  196. user_service = UserCRUD(auth)
  197. await user_service.delete(ids=[employee.user_id])
  198. await crud.delete_by_employee_id(employee_id)
  199. return EmployeeOperationOutSchema(
  200. employee_id=employee_id,
  201. )
  202. @classmethod
  203. async def invite_query_service(
  204. cls, auth: AuthSchema, data: EmployeeInviteQuerySchema
  205. ) -> EmployeeInviteQueryOutSchema:
  206. """
  207. 获取员工签约激活链接
  208. 调用: alipay.commerce.ec.employee.invite.query
  209. """
  210. from alipay.aop.api.request.AlipayCommerceEcEmployeeInviteQueryRequest import AlipayCommerceEcEmployeeInviteQueryRequest
  211. from alipay.aop.api.domain.AlipayCommerceEcEmployeeInviteQueryModel import AlipayCommerceEcEmployeeInviteQueryModel
  212. from alipay.aop.api.response.AlipayCommerceEcEmployeeInviteQueryResponse import AlipayCommerceEcEmployeeInviteQueryResponse
  213. model = AlipayCommerceEcEmployeeInviteQueryModel()
  214. model.enterprise_id = data.enterprise_id
  215. model.employee_id = data.employee_id
  216. model.page_content_code = data.page_content_code
  217. model.withholding_sign_str = data.withholding_sign_str
  218. model.create_share_code = data.create_share_code
  219. request = AlipayCommerceEcEmployeeInviteQueryRequest()
  220. request.biz_model = model
  221. client = AlipayClient.get_client()
  222. response = client.execute(request)
  223. if not response:
  224. raise CustomException(msg="获取员工签约激活链接失败: 无响应")
  225. result = AlipayCommerceEcEmployeeInviteQueryResponse()
  226. result.parse_response_content(response)
  227. if not result.is_success():
  228. log.error(f"支付宝接口调用失败: {result.code} - {result.msg}")
  229. raise CustomException(msg=f"获取员工签约激活链接失败: {result.msg}")
  230. return EmployeeInviteQueryOutSchema(
  231. enterprise_id=result.enterprise_id or data.enterprise_id,
  232. sign_url=result.sign_url or "",
  233. mini_app_sign_url=result.mini_app_sign_url or "",
  234. share_code=getattr(result, 'share_code', None)
  235. )
  236. @classmethod
  237. async def update_employee_from_alipay(cls, auth: AuthSchema, data: EmployeeCreateOrUpdateSchema):
  238. """
  239. 从支付宝更新员工信息
  240. """
  241. # 先查询支付宝员工信息
  242. employee = await cls.detail_service(
  243. auth=auth,
  244. employee_id=data.employee_id,
  245. employee_email=data.employee_email,
  246. employee_mobile=data.employee_mobile,
  247. enterprise_id=data.enterprise_id
  248. )
  249. if not employee :
  250. raise CustomException(msg=f"员工 {data.employee_id} 不存在")
  251. if hasattr(employee, 'employee_id') and employee['employee_id'] != data.employee_id:
  252. raise CustomException(msg=f"员工 {data.employee_id} 不存在")
  253. crud = EmployeeCRUD(auth)
  254. await crud.update_by(
  255. employee_mobile=data.employee_mobile,
  256. employee_email=data.employee_email,
  257. identity_open_id=data.identity_open_id,
  258. data=data.model_dump(exclude_none=True)
  259. )