service.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  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}_admin"
  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=password),
  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. except CustomException:
  83. raise
  84. except Exception as e:
  85. log.error(f"为租户[{tenant_obj.name}]创建初始管理员失败: {e!s}")
  86. raise CustomException(msg="创建租户初始管理员失败")
  87. log.info(
  88. f"为租户[{tenant_obj.name}]创建初始管理员成功,用户名: {username},临时密码: {password}"
  89. )
  90. @classmethod
  91. async def update_service(cls, auth: AuthSchema, id: int, data: TenantUpdateSchema) -> dict:
  92. ensure_platform_tenant_management(auth)
  93. obj = await TenantCRUD(auth).get_by_id_crud(id=id)
  94. if not obj:
  95. raise CustomException(msg="租户不存在")
  96. if id == 1:
  97. if data.code is not None and data.code != obj.code:
  98. raise CustomException(msg="系统租户编码不可修改")
  99. if data.status is not None and data.status == "1":
  100. raise CustomException(msg="系统租户不允许禁用")
  101. if data.name is not None:
  102. exist = await TenantCRUD(auth).get(name=data.name)
  103. if exist and exist.id != id:
  104. raise CustomException(msg="更新失败,名称重复")
  105. if data.code is not None:
  106. exist = await TenantCRUD(auth).get(code=data.code)
  107. if exist and exist.id != id:
  108. raise CustomException(msg="更新失败,编码重复")
  109. updated = await TenantCRUD(auth).update_crud(id=id, data=data)
  110. if not updated:
  111. raise CustomException(msg="更新失败")
  112. return TenantOutSchema.model_validate(updated).model_dump()
  113. @classmethod
  114. async def delete_service(cls, auth: AuthSchema, ids: list[int]) -> None:
  115. ensure_platform_tenant_management(auth)
  116. if not ids:
  117. raise CustomException(msg="删除失败,删除对象不能为空")
  118. if 1 in ids:
  119. raise CustomException(msg="系统租户不允许删除")
  120. for id in ids:
  121. obj = await TenantCRUD(auth).get_by_id_crud(id=id)
  122. if not obj:
  123. continue
  124. for tid in ids:
  125. reasons: list[str] = []
  126. if await UserCRUD(auth).list(search={"tenant_id": tid}):
  127. reasons.append("用户")
  128. if await DeptCRUD(auth).list(search={"tenant_id": tid}):
  129. reasons.append("部门")
  130. if await RoleCRUD(auth).list(search={"tenant_id": tid}):
  131. reasons.append("角色")
  132. if await PositionCRUD(auth).list(search={"tenant_id": tid}):
  133. reasons.append("岗位")
  134. if reasons:
  135. raise CustomException(
  136. msg=f"租户 ID={tid} 下仍有关联数据({','.join(reasons)}),请先清理后再删除"
  137. )
  138. await TenantCRUD(auth).delete_crud(ids=ids)
  139. @classmethod
  140. async def set_available_service(cls, auth: AuthSchema, data: BatchSetAvailable) -> None:
  141. ensure_platform_tenant_management(auth)
  142. if data.status == "1" and 1 in data.ids:
  143. raise CustomException(msg="系统租户不允许禁用")
  144. await TenantCRUD(auth).set_available_crud(ids=data.ids, status=data.status)