| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162 |
- from decimal import Decimal
- import random
- import string
- from app.api.v1.module_system.auth.schema import AuthSchema
- from app.api.v1.module_system.dept.crud import DeptCRUD
- from app.api.v1.module_system.position.crud import PositionCRUD
- from app.api.v1.module_system.role.crud import RoleCRUD
- from app.api.v1.module_system.tenant.tools.access import ensure_platform_tenant_management
- from app.api.v1.module_system.user.crud import UserCRUD
- from app.core.base_schema import BatchSetAvailable
- from app.core.exceptions import CustomException
- from app.core.logger import log
- from app.plugin.module_payment.points.schema import PointsCreateSchema
- from app.plugin.module_payment.points.service import PointsService
- from app.utils.hash_bcrpy_util import PwdUtil
- from .crud import TenantCRUD
- from .model import TenantModel
- from .schema import TenantCreateSchema, TenantOutSchema, TenantQueryParam, TenantUpdateSchema
- class TenantService:
- """租户管理模块服务层"""
- @classmethod
- async def detail_service(cls, auth: AuthSchema, id: int) -> dict:
- ensure_platform_tenant_management(auth)
- obj = await TenantCRUD(auth).get_by_id_crud(id=id)
- if not obj:
- raise CustomException(msg="租户不存在")
- return TenantOutSchema.model_validate(obj).model_dump()
- @classmethod
- async def page_service(
- cls,
- auth: AuthSchema,
- page_no: int,
- page_size: int,
- search: TenantQueryParam | None = None,
- order_by: list[dict[str, str]] | None = None,
- ) -> dict:
- return await TenantCRUD(auth).page_crud(
- offset=(page_no - 1) * page_size,
- limit=page_size,
- order_by=order_by or [{"id": "asc"}],
- search=search.__dict__ if search else {},
- out_schema=TenantOutSchema,
- )
- @classmethod
- async def create_service(cls, auth: AuthSchema, data: TenantCreateSchema) -> dict:
- ensure_platform_tenant_management(auth)
- if await TenantCRUD(auth).get(name=data.name):
- raise CustomException(msg="创建失败,名称已存在")
- if await TenantCRUD(auth).get(code=data.code):
- raise CustomException(msg="创建失败,编码已存在")
- tenant_obj = await TenantCRUD(auth).create_crud(data=data)
- if not tenant_obj:
- raise CustomException(msg="创建租户失败")
- log.info(f"创建租户成功: {tenant_obj.name},编码: {tenant_obj.code}")
- # 创建初始管理员
- await cls._create_tenant_admin_user(auth, tenant_obj)
- # 创建积分账户
- await PointsService.create_points_service(auth, PointsCreateSchema(tenant_id=tenant_obj.id, points=Decimal("0.00")))
- await auth.db.refresh(tenant_obj)
- return TenantOutSchema.model_validate(tenant_obj).model_dump()
- @classmethod
- async def _create_tenant_admin_user(cls, auth: AuthSchema, tenant_obj: TenantModel) -> None:
- username = f"{tenant_obj.code}"
- if await UserCRUD(auth).get_by_username_crud(username=username):
- raise CustomException(msg=f"初始管理员用户名已存在: {username},请更换租户编码后重试")
- password_length = 12
- characters = string.ascii_letters + string.digits + "!@#$%^&*"
- password = "".join(random.choice(characters) for _ in range(password_length))
- admin_data = {
- "username": username,
- "password": PwdUtil.set_password_hash(password=tenant_obj.code),
- "name": f"{tenant_obj.name}管理员",
- "tenant_id": tenant_obj.id,
- "status": "0",
- "is_superuser": False,
- }
- log.info(f"为租户[{tenant_obj.name}]创建初始管理员数据: {admin_data}")
- try:
- user_obj = await UserCRUD(auth).create(data=admin_data, skip_tenant_id=True)
- if not user_obj:
- raise CustomException(msg="创建租户初始管理员失败")
- await UserCRUD(auth).set_user_roles_crud(user_ids=[user_obj.id], role_ids=[2,])
- except CustomException:
- raise
- except Exception as e:
- log.error(f"为租户[{tenant_obj.name}]创建初始管理员失败: {e!s}")
- raise CustomException(msg="创建租户初始管理员失败")
- log.info(
- f"为租户[{tenant_obj.name}]创建初始管理员成功,用户名: {username},临时密码: {password}"
- )
- @classmethod
- async def update_service(cls, auth: AuthSchema, id: int, data: TenantUpdateSchema) -> dict:
- ensure_platform_tenant_management(auth)
- obj = await TenantCRUD(auth).get_by_id_crud(id=id)
- if not obj:
- raise CustomException(msg="租户不存在")
- if id == 1:
- if data.code is not None and data.code != obj.code:
- raise CustomException(msg="系统租户编码不可修改")
- if data.status is not None and data.status == "1":
- raise CustomException(msg="系统租户不允许禁用")
- if data.name is not None:
- exist = await TenantCRUD(auth).get(name=data.name)
- if exist and exist.id != id:
- raise CustomException(msg="更新失败,名称重复")
- if data.code is not None:
- exist = await TenantCRUD(auth).get(code=data.code)
- if exist and exist.id != id:
- raise CustomException(msg="更新失败,编码重复")
- updated = await TenantCRUD(auth).update_crud(id=id, data=data)
- if not updated:
- raise CustomException(msg="更新失败")
- return TenantOutSchema.model_validate(updated).model_dump()
- @classmethod
- async def delete_service(cls, auth: AuthSchema, ids: list[int]) -> None:
- ensure_platform_tenant_management(auth)
- if not ids:
- raise CustomException(msg="删除失败,删除对象不能为空")
- if 1 in ids:
- raise CustomException(msg="系统租户不允许删除")
- for id in ids:
- obj = await TenantCRUD(auth).get_by_id_crud(id=id)
- if not obj:
- continue
- for tid in ids:
- reasons: list[str] = []
- if await UserCRUD(auth).list(search={"tenant_id": tid}):
- reasons.append("用户")
- if await DeptCRUD(auth).list(search={"tenant_id": tid}):
- reasons.append("部门")
- if await RoleCRUD(auth).list(search={"tenant_id": tid}):
- reasons.append("角色")
- if await PositionCRUD(auth).list(search={"tenant_id": tid}):
- reasons.append("岗位")
- if reasons:
- raise CustomException(
- msg=f"租户 ID={tid} 下仍有关联数据({','.join(reasons)}),请先清理后再删除"
- )
- await TenantCRUD(auth).delete_crud(ids=ids)
- @classmethod
- async def set_available_service(cls, auth: AuthSchema, data: BatchSetAvailable) -> None:
- ensure_platform_tenant_management(auth)
- if data.status == "1" and 1 in data.ids:
- raise CustomException(msg="系统租户不允许禁用")
- await TenantCRUD(auth).set_available_crud(ids=data.ids, status=data.status)
|