| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226 |
- """质检物料金额查看授权 CRUD(sys_user_role 绑定专用角色)。"""
- from __future__ import annotations
- from datetime import datetime
- from typing import Any, Dict, List, Optional, Tuple
- from sqlalchemy import and_, or_
- from sqlalchemy.orm import Session
- from app.core.qc_material_amount_auth_constants import (
- QC_MATERIAL_AMOUNT_VIEW_ROLE_ID,
- QC_MATERIAL_AMOUNT_VIEW_ROLE_NAME,
- QC_MATERIAL_AMOUNT_AUTH_DEPT_NAME,
- )
- from app.core.data_scope import _get_child_dept_ids
- from app.core.utils import generate_uuid
- from app.models.models import SysDept, SysRole, SysUser, SysUserRole
- def get_amount_view_role(db: Session, tenant_no: str) -> Optional[SysRole]:
- row = (
- db.query(SysRole)
- .filter(
- SysRole.id == QC_MATERIAL_AMOUNT_VIEW_ROLE_ID,
- SysRole.tenant_no == tenant_no,
- SysRole.del_flag == 0,
- SysRole.status == "1",
- )
- .first()
- )
- if row:
- return row
- return (
- db.query(SysRole)
- .filter(
- SysRole.role_name == QC_MATERIAL_AMOUNT_VIEW_ROLE_NAME,
- SysRole.tenant_no == tenant_no,
- SysRole.del_flag == 0,
- SysRole.status == "1",
- )
- .first()
- )
- def _get_auth_dept_id(db: Session, tenant_no: str) -> Optional[str]:
- row = (
- db.query(SysDept.id)
- .filter(
- SysDept.dept_name == QC_MATERIAL_AMOUNT_AUTH_DEPT_NAME,
- SysDept.tenant_no == tenant_no,
- SysDept.del_flag == 0,
- SysDept.status == "1",
- )
- .first()
- )
- return str(row[0]).strip() if row and row[0] else None
- def _assert_user_in_auth_dept(db: Session, user: SysUser, tenant_no: str) -> None:
- dept_id = _get_auth_dept_id(db, tenant_no)
- if not dept_id:
- raise ValueError(f"未找到部门「{QC_MATERIAL_AMOUNT_AUTH_DEPT_NAME}」")
- user_dept_id = (user.dept_id or "").strip()
- if not user_dept_id:
- raise ValueError(f"仅可授权「{QC_MATERIAL_AMOUNT_AUTH_DEPT_NAME}」下的用户")
- allowed = set(_get_child_dept_ids(db, dept_id, tenant_no))
- if user_dept_id not in allowed:
- raise ValueError(f"仅可授权「{QC_MATERIAL_AMOUNT_AUTH_DEPT_NAME}」下的用户")
- def _user_has_role_binding(db: Session, user_id: str, role_id: str, tenant_no: str) -> bool:
- return (
- db.query(SysUserRole)
- .filter(
- SysUserRole.user_id == user_id,
- SysUserRole.role_id == role_id,
- SysUserRole.tenant_no == tenant_no,
- SysUserRole.del_flag == 0,
- )
- .first()
- is not None
- )
- def _row_to_dict(user: SysUser, dept_name: str, grant_time: Optional[datetime]) -> Dict[str, Any]:
- return {
- "id": user.id,
- "userId": user.id,
- "userNo": user.user_no,
- "nickName": user.nick_name,
- "phoneNo": user.phone_no or "",
- "deptName": dept_name,
- "status": user.status,
- "grantTime": grant_time.strftime("%Y-%m-%d %H:%M:%S") if grant_time else "",
- }
- def list_authorized_users(
- db: Session,
- *,
- tenant_no: str,
- page: int = 1,
- page_size: int = 10,
- keyword: Optional[str] = None,
- ) -> Tuple[List[Dict[str, Any]], int]:
- role = get_amount_view_role(db, tenant_no)
- if not role:
- return [], 0
- q = (
- db.query(SysUser, SysUserRole.create_time)
- .join(
- SysUserRole,
- and_(
- SysUserRole.user_id == SysUser.id,
- SysUserRole.role_id == role.id,
- SysUserRole.tenant_no == tenant_no,
- SysUserRole.del_flag == 0,
- ),
- )
- .filter(SysUser.del_flag == 0, SysUser.tenant_no == tenant_no)
- )
- kw = (keyword or "").strip()
- if kw:
- like = f"%{kw}%"
- q = q.filter(
- or_(
- SysUser.user_no.like(like),
- SysUser.nick_name.like(like),
- SysUser.phone_no.like(like),
- )
- )
- total = q.count()
- rows = (
- q.order_by(SysUserRole.create_time.desc())
- .offset((page - 1) * page_size)
- .limit(page_size)
- .all()
- )
- dept_ids = list({u.dept_id for u, _ in rows if u.dept_id})
- dept_map: Dict[str, str] = {}
- if dept_ids:
- for d in db.query(SysDept).filter(SysDept.id.in_(dept_ids), SysDept.del_flag == 0).all():
- dept_map[d.id] = d.dept_name or ""
- items = [
- _row_to_dict(u, dept_map.get(u.dept_id or "", ""), grant_time)
- for u, grant_time in rows
- ]
- return items, total
- def grant_amount_view_role(
- db: Session,
- *,
- tenant_no: str,
- user_id: str,
- operator_id: Optional[str],
- ) -> bool:
- """绑定专用角色;已绑定则幂等返回 False(表示未新增)。"""
- role = get_amount_view_role(db, tenant_no)
- if not role:
- raise ValueError("未找到「质检物料金额查看」角色,请先执行 migrate-qc-material-amount-auth.sql")
- user = (
- db.query(SysUser)
- .filter(SysUser.id == user_id, SysUser.tenant_no == tenant_no, SysUser.del_flag == 0)
- .first()
- )
- if not user:
- raise ValueError("用户不存在")
- if user.status != "1":
- raise ValueError("用户已停用,无法授权")
- _assert_user_in_auth_dept(db, user, tenant_no)
- if _user_has_role_binding(db, user_id, role.id, tenant_no):
- return False
- now = datetime.now()
- db.add(
- SysUserRole(
- id=generate_uuid(),
- user_id=user_id,
- role_id=role.id,
- tenant_no=tenant_no,
- order_num=0,
- remark=None,
- create_by=operator_id,
- create_dept_id="",
- create_time=now,
- update_by=operator_id,
- update_time=now,
- del_flag=0,
- )
- )
- db.commit()
- return True
- def revoke_amount_view_role(
- db: Session,
- *,
- tenant_no: str,
- user_id: str,
- operator_id: Optional[str],
- ) -> bool:
- """解除专用角色绑定;未绑定则返回 False。"""
- role = get_amount_view_role(db, tenant_no)
- if not role:
- raise ValueError("未找到「质检物料金额查看」角色")
- now = datetime.now()
- updated = (
- db.query(SysUserRole)
- .filter(
- SysUserRole.user_id == user_id,
- SysUserRole.role_id == role.id,
- SysUserRole.tenant_no == tenant_no,
- SysUserRole.del_flag == 0,
- )
- .update({"del_flag": 1, "update_by": operator_id, "update_time": now})
- )
- if updated:
- db.commit()
- return True
- return False
|