service.py 7.3 KB

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