service.py 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. from decimal import Decimal
  2. import random
  3. import string
  4. from app.api.v1.module_system.auth.schema import AuthSchema
  5. from app.api.v1.module_system.dept.crud import DeptCRUD
  6. from app.api.v1.module_system.position.crud import PositionCRUD
  7. from app.api.v1.module_system.role.crud import RoleCRUD
  8. from app.api.v1.module_system.tenant.tools.access import ensure_platform_tenant_management
  9. from app.api.v1.module_system.user.crud import UserCRUD
  10. from app.core.base_schema import BatchSetAvailable
  11. from app.core.exceptions import CustomException
  12. from app.core.logger import log
  13. from app.plugin.module_payment.points.schema import PointsCreateSchema
  14. from app.plugin.module_payment.points.service import PointsService
  15. from app.utils.hash_bcrpy_util import PwdUtil
  16. from .crud import TenantCRUD
  17. from .model import TenantModel
  18. from .schema import TenantCreateSchema, TenantOutSchema, TenantQueryParam, TenantUpdateSchema
  19. class TenantService:
  20. """租户管理模块服务层"""
  21. @classmethod
  22. async def detail_service(cls, auth: AuthSchema, id: int) -> dict:
  23. ensure_platform_tenant_management(auth)
  24. obj = await TenantCRUD(auth).get_by_id_crud(id=id)
  25. if not obj:
  26. raise CustomException(msg="租户不存在")
  27. return TenantOutSchema.model_validate(obj).model_dump()
  28. @classmethod
  29. async def page_service(
  30. cls,
  31. auth: AuthSchema,
  32. page_no: int,
  33. page_size: int,
  34. search: TenantQueryParam | None = None,
  35. order_by: list[dict[str, str]] | None = None,
  36. ) -> dict:
  37. return await TenantCRUD(auth).page_crud(
  38. offset=(page_no - 1) * page_size,
  39. limit=page_size,
  40. order_by=order_by or [{"id": "asc"}],
  41. search=search.__dict__ if search else {},
  42. out_schema=TenantOutSchema,
  43. )
  44. @classmethod
  45. async def create_service(cls, auth: AuthSchema, data: TenantCreateSchema) -> dict:
  46. ensure_platform_tenant_management(auth)
  47. if await TenantCRUD(auth).get(name=data.name):
  48. raise CustomException(msg="创建失败,名称已存在")
  49. if await TenantCRUD(auth).get(code=data.code):
  50. raise CustomException(msg="创建失败,编码已存在")
  51. tenant_obj = await TenantCRUD(auth).create_crud(data=data)
  52. if not tenant_obj:
  53. raise CustomException(msg="创建租户失败")
  54. log.info(f"创建租户成功: {tenant_obj.name},编码: {tenant_obj.code}")
  55. # 创建初始管理员
  56. await cls._create_tenant_admin_user(auth, tenant_obj)
  57. # 创建积分账户
  58. await PointsService.create_points_service(auth, PointsCreateSchema(tenant_id=tenant_obj.id, points=Decimal("0.00")))
  59. await auth.db.refresh(tenant_obj)
  60. return TenantOutSchema.model_validate(tenant_obj).model_dump()
  61. @classmethod
  62. async def _create_tenant_admin_user(cls, auth: AuthSchema, tenant_obj: TenantModel) -> None:
  63. username = f"{tenant_obj.code}"
  64. if await UserCRUD(auth).get_by_username_crud(username=username):
  65. raise CustomException(msg=f"初始管理员用户名已存在: {username},请更换租户编码后重试")
  66. password_length = 12
  67. characters = string.ascii_letters + string.digits + "!@#$%^&*"
  68. password = "".join(random.choice(characters) for _ in range(password_length))
  69. admin_data = {
  70. "username": username,
  71. "password": PwdUtil.set_password_hash(password=tenant_obj.code),
  72. "name": f"{tenant_obj.name}管理员",
  73. "tenant_id": tenant_obj.id,
  74. "status": "0",
  75. "is_superuser": False,
  76. }
  77. log.info(f"为租户[{tenant_obj.name}]创建初始管理员数据: {admin_data}")
  78. try:
  79. user_obj = await UserCRUD(auth).create(data=admin_data, skip_tenant_id=True)
  80. if not user_obj:
  81. raise CustomException(msg="创建租户初始管理员失败")
  82. await UserCRUD(auth).set_user_roles_crud(user_ids=[user_obj.id], role_ids=[2,])
  83. except CustomException:
  84. raise
  85. except Exception as e:
  86. log.error(f"为租户[{tenant_obj.name}]创建初始管理员失败: {e!s}")
  87. raise CustomException(msg="创建租户初始管理员失败")
  88. log.info(
  89. f"为租户[{tenant_obj.name}]创建初始管理员成功,用户名: {username},临时密码: {password}"
  90. )
  91. @classmethod
  92. async def update_service(cls, auth: AuthSchema, id: int, data: TenantUpdateSchema) -> dict:
  93. ensure_platform_tenant_management(auth)
  94. obj = await TenantCRUD(auth).get_by_id_crud(id=id)
  95. if not obj:
  96. raise CustomException(msg="租户不存在")
  97. if id == 1:
  98. if data.code is not None and data.code != obj.code:
  99. raise CustomException(msg="系统租户编码不可修改")
  100. if data.status is not None and data.status == "1":
  101. raise CustomException(msg="系统租户不允许禁用")
  102. if data.name is not None:
  103. exist = await TenantCRUD(auth).get(name=data.name)
  104. if exist and exist.id != id:
  105. raise CustomException(msg="更新失败,名称重复")
  106. if data.code is not None:
  107. exist = await TenantCRUD(auth).get(code=data.code)
  108. if exist and exist.id != id:
  109. raise CustomException(msg="更新失败,编码重复")
  110. updated = await TenantCRUD(auth).update_crud(id=id, data=data)
  111. if not updated:
  112. raise CustomException(msg="更新失败")
  113. return TenantOutSchema.model_validate(updated).model_dump()
  114. @classmethod
  115. async def delete_service(cls, auth: AuthSchema, ids: list[int]) -> None:
  116. ensure_platform_tenant_management(auth)
  117. if not ids:
  118. raise CustomException(msg="删除失败,删除对象不能为空")
  119. if 1 in ids:
  120. raise CustomException(msg="系统租户不允许删除")
  121. for id in ids:
  122. obj = await TenantCRUD(auth).get_by_id_crud(id=id)
  123. if not obj:
  124. continue
  125. for tid in ids:
  126. reasons: list[str] = []
  127. if await UserCRUD(auth).list(search={"tenant_id": tid}):
  128. reasons.append("用户")
  129. if await DeptCRUD(auth).list(search={"tenant_id": tid}):
  130. reasons.append("部门")
  131. if await RoleCRUD(auth).list(search={"tenant_id": tid}):
  132. reasons.append("角色")
  133. if await PositionCRUD(auth).list(search={"tenant_id": tid}):
  134. reasons.append("岗位")
  135. if reasons:
  136. raise CustomException(
  137. msg=f"租户 ID={tid} 下仍有关联数据({','.join(reasons)}),请先清理后再删除"
  138. )
  139. await TenantCRUD(auth).delete_crud(ids=ids)
  140. @classmethod
  141. async def set_available_service(cls, auth: AuthSchema, data: BatchSetAvailable) -> None:
  142. ensure_platform_tenant_management(auth)
  143. if data.status == "1" and 1 in data.ids:
  144. raise CustomException(msg="系统租户不允许禁用")
  145. await TenantCRUD(auth).set_available_crud(ids=data.ids, status=data.status)