fix(incubator): 完善昆明市大学生创业园权限矩阵
- resolve_identity: 子管理员(park_members.member_type=admin, active)纳入园区管理方 - 月报(create/update/submit/reopen): 仅企业管理员(is_company_admin)可操作 - list_company_members: 仅企业管理员可查看本企业成员(所有成员权限) - 请假: list/get 企业管理员看本企业全部; review_leave 企业管理员可审批本企业请假 - 普通企业成员: 仅请假/预约共享区域(维持); 无权限账号一律拒绝
This commit is contained in:
+40
-10
@@ -29,6 +29,7 @@ from ..infrastructure.models import (
|
||||
IncubatorSetting,
|
||||
IncubatorSharedArea,
|
||||
ParkCompany,
|
||||
ParkMember,
|
||||
ParkTenant,
|
||||
User,
|
||||
)
|
||||
@@ -106,6 +107,19 @@ async def resolve_identity(db, user: dict) -> Identity:
|
||||
return Identity(is_manager=True, tenant_id=tid, company_id="",
|
||||
company_name="", role="carrier:admin", user_id=uid,
|
||||
user_name=user_name)
|
||||
# —— 子管理员:park_members.member_type=admin 且 active(园区绑定子管理员)——
|
||||
sub_admin = (await db.session.execute(
|
||||
select(ParkMember).where(
|
||||
ParkMember.user_id == uid,
|
||||
ParkMember.park_id == tid,
|
||||
ParkMember.member_type == "admin",
|
||||
ParkMember.status == "active",
|
||||
)
|
||||
)).scalar_one_or_none()
|
||||
if sub_admin is not None:
|
||||
return Identity(is_manager=True, tenant_id=tid, company_id="",
|
||||
company_name="", role="carrier:sub_admin", user_id=uid,
|
||||
user_name=user_name)
|
||||
# 兜底:平台运营方(operator)账号可管理本园区(天然全权限)。
|
||||
# 说明:本应用按“园区管理员”语义放行平台运营账号,便于运营方直接查看/
|
||||
# 审核全园区申请与月报;若需收紧,仅保留 yunpeng 绑定即可删去该分支。
|
||||
@@ -231,10 +245,12 @@ def _check_tenant_access(identity: Identity, tenant_id: str, company_id: str) ->
|
||||
|
||||
|
||||
async def create_report(db, identity: Identity, data: dict) -> dict:
|
||||
"""新建/保存草稿(提交方)。同一企业+月份已存在则返回既有记录。"""
|
||||
"""新建/保存草稿(企业管理员)。同一企业+月份已存在则返回既有记录。"""
|
||||
require_identity(identity)
|
||||
if identity.is_manager:
|
||||
raise PermissionError("管理方不填报报告")
|
||||
if not identity.is_company_admin:
|
||||
raise PermissionError("仅企业管理员可填报月报")
|
||||
month = str(data.get("report_month", "")).strip()
|
||||
if not month:
|
||||
raise ValueError("report_month 必填(如 2026-08)")
|
||||
@@ -289,8 +305,10 @@ def _apply_report_fields(r: IncubatorMonthlyReport, data: dict) -> None:
|
||||
|
||||
|
||||
async def update_report(db, identity: Identity, report_id: str, data: dict) -> dict:
|
||||
"""更新报告(draft,或 submitted 未审核可撤回重改)。"""
|
||||
"""更新报告(draft,或 submitted 未审核可撤回重改;仅企业管理员)。"""
|
||||
require_identity(identity)
|
||||
if not identity.is_company_admin:
|
||||
raise PermissionError("仅企业管理员可编辑本企业月报")
|
||||
r = await db.session.get(IncubatorMonthlyReport, report_id)
|
||||
if r is None:
|
||||
raise LookupError("报告不存在")
|
||||
@@ -307,8 +325,10 @@ async def update_report(db, identity: Identity, report_id: str, data: dict) -> d
|
||||
|
||||
|
||||
async def submit_report(db, identity: Identity, report_id: str) -> dict:
|
||||
"""提交审核:draft → submitted。"""
|
||||
"""提交审核:draft → submitted(仅企业管理员)。"""
|
||||
require_identity(identity)
|
||||
if not identity.is_company_admin:
|
||||
raise PermissionError("仅企业管理员可提交本企业月报")
|
||||
r = await db.session.get(IncubatorMonthlyReport, report_id)
|
||||
if r is None:
|
||||
raise LookupError("报告不存在")
|
||||
@@ -325,8 +345,10 @@ async def submit_report(db, identity: Identity, report_id: str) -> dict:
|
||||
|
||||
|
||||
async def reopen_report(db, identity: Identity, report_id: str) -> dict:
|
||||
"""撤回:submitted(未审核) → draft,允许重改。"""
|
||||
"""撤回:submitted(未审核) → draft,允许重改(仅企业管理员)。"""
|
||||
require_identity(identity)
|
||||
if not identity.is_company_admin:
|
||||
raise PermissionError("仅企业管理员可撤回本企业月报")
|
||||
r = await db.session.get(IncubatorMonthlyReport, report_id)
|
||||
if r is None:
|
||||
raise LookupError("报告不存在")
|
||||
@@ -806,8 +828,10 @@ async def get_company_profile(db, identity: Identity) -> dict:
|
||||
|
||||
|
||||
async def list_company_members(db, identity: Identity) -> dict:
|
||||
"""企业绑定成员列表(联系人自动填入用):姓名/手机/职务/是否管理员。"""
|
||||
"""企业绑定成员列表(联系人自动填入用,仅企业管理员可查看全部成员)。"""
|
||||
require_identity(identity)
|
||||
if not identity.is_company_admin:
|
||||
raise PermissionError("仅企业管理员可查看本企业成员")
|
||||
if not identity.company_id:
|
||||
return {"items": [], "total": 0}
|
||||
rows = (await db.session.execute(
|
||||
@@ -1102,12 +1126,14 @@ LEAVE_STATUSES = ("pending", "approved", "rejected", "cancelled")
|
||||
|
||||
async def list_leaves(db, identity: Identity, *, status: str = "",
|
||||
company_id: str = "") -> dict:
|
||||
"""请假列表:园区管理员=全园区;企业成员=本人。"""
|
||||
"""请假列表:园区管理员=全园区;企业管理员=本企业;普通成员=本人。"""
|
||||
require_identity(identity)
|
||||
stmt = select(IncubatorLeave).where(IncubatorLeave.tenant_id == identity.tenant_id)
|
||||
if identity.is_manager:
|
||||
if company_id:
|
||||
stmt = stmt.where(IncubatorLeave.company_id == company_id)
|
||||
elif identity.is_company_admin:
|
||||
stmt = stmt.where(IncubatorLeave.company_id == identity.company_id)
|
||||
else:
|
||||
stmt = stmt.where(IncubatorLeave.user_id == identity.user_id)
|
||||
if status and status in LEAVE_STATUSES:
|
||||
@@ -1123,7 +1149,9 @@ async def get_leave(db, identity: Identity, leave_id: str) -> dict:
|
||||
r = await db.session.get(IncubatorLeave, leave_id)
|
||||
if r is None or r.tenant_id != identity.tenant_id:
|
||||
raise LookupError("请假单不存在")
|
||||
if not identity.is_manager and r.user_id != identity.user_id:
|
||||
if not identity.is_manager and not (identity.is_company_admin
|
||||
and r.company_id == identity.company_id) \
|
||||
and r.user_id != identity.user_id:
|
||||
raise LookupError("请假单不存在")
|
||||
return _leave_to_dict(r)
|
||||
|
||||
@@ -1165,15 +1193,17 @@ async def create_leave(db, identity: Identity, body: dict) -> dict:
|
||||
|
||||
async def review_leave(db, identity: Identity, leave_id: str,
|
||||
action: str, comment: str = "") -> dict:
|
||||
"""审批请假:仅园区管理员(carrier / 园区绑定管理员)。"""
|
||||
"""审批请假:园区管理员(carrier / 园区绑定子管理员)或本企业管理员。"""
|
||||
require_identity(identity)
|
||||
if not identity.is_manager:
|
||||
raise PermissionError("仅园区管理员可审批请假")
|
||||
if not identity.is_manager and not identity.is_company_admin:
|
||||
raise PermissionError("仅园区管理员或本企业管理员可审批请假")
|
||||
if action not in ("approve", "reject"):
|
||||
raise ValueError("action 仅支持 approve / reject")
|
||||
r = await db.session.get(IncubatorLeave, leave_id)
|
||||
if r is None or r.tenant_id != identity.tenant_id:
|
||||
raise LookupError("请假单不存在")
|
||||
if not identity.is_manager and r.company_id != identity.company_id:
|
||||
raise PermissionError("仅可审批本企业请假")
|
||||
if r.status != "pending":
|
||||
raise ValueError(f"当前状态 {r.status} 不可审批")
|
||||
r.status = "approved" if action == "approve" else "rejected"
|
||||
|
||||
Reference in New Issue
Block a user