"feat(gvsdsdk): 新增 PositionManager 服务层并接入职务系统 API

- PositionManager 提供职务/岗位模板/模板权限共 11 个服务方法
- position.py 11 处裸 ORM 操作全部改用服务层
- 消除职务系统跨表裸查询,统一走 gvsdsdk"
This commit is contained in:
TermiNexus committed 2026-08-07 01:21:05 +08:00
1 parent 62b6ae08ed
commit e27f3d3dd6
2 files changed
+191 -61

No files matched your search

+24 -59
View File
@@ -11,6 +11,7 @@ from gvsds.apps.gerp.serializers import (
PositionTemplateSerializer, PositionTemplateCreateSerializer, PositionTemplateUpdateSerializer,
PositionTemplatePermissionSerializer, PositionTemplatePermAssignSerializer, PositionTemplatePermRemoveSerializer,
)
from gvsdsdk.auth.managers import PositionManager
class PositionListView(ELTAuthenticatedAPIView):
@@ -21,7 +22,7 @@ class PositionListView(ELTAuthenticatedAPIView):
if not tenant_uuid:
return Response({'Code': 400, 'Msg': 'TenantUUID 必填', 'Data': None}, status=400)
positions = Position.objects.filter(TenantUUID=tenant_uuid, PositionStatus=1)
positions = PositionManager.GetPositionsForTenant(tenant_uuid)
serializer = PositionSerializer(positions, many=True)
return Response({'Code': 200, 'Msg': 'OK', 'Data': serializer.data})
@@ -62,17 +63,14 @@ class PositionUpdateView(ELTAuthenticatedAPIView):
return Response({'Code': 400, 'Msg': serializer.errors, 'Data': None}, status=400)
data = serializer.validated_data
try:
position = Position.objects.get(PositionUUID=data['PositionUUID'])
except Position.DoesNotExist:
position = PositionManager.GetPositionByUUID(data['PositionUUID'])
if position is None:
return Response({'Code': 404, 'Msg': '职务不存在', 'Data': None}, status=404)
for field in ('PositionName', 'PositionCode', 'PositionLevel', 'PositionStatus', 'PositionDesc'):
if field in data:
setattr(position, field, data[field])
import datetime
position.UpdateTime = datetime.datetime.utcnow()
position.save(update_fields=[f for f in data if f != 'PositionUUID'] + ['UpdateTime'])
position = PositionManager.UpdatePosition(
data['PositionUUID'],
**{f: data[f] for f in ('PositionName', 'PositionCode', 'PositionLevel', 'PositionStatus', 'PositionDesc') if f in data},
)
return Response({'Code': 200, 'Msg': '更新成功', 'Data': PositionSerializer(position).data})
@@ -84,15 +82,8 @@ class PositionDeleteView(ELTAuthenticatedAPIView):
if not position_uuid:
return Response({'Code': 400, 'Msg': 'PositionUUID 必填', 'Data': None}, status=400)
try:
position = Position.objects.get(PositionUUID=position_uuid)
except Position.DoesNotExist:
if not PositionManager.DeletePosition(position_uuid):
return Response({'Code': 404, 'Msg': '职务不存在', 'Data': None}, status=404)
position.PositionStatus = 0
import datetime
position.UpdateTime = datetime.datetime.utcnow()
position.save(update_fields=['PositionStatus', 'UpdateTime'])
return Response({'Code': 200, 'Msg': '删除成功', 'Data': None})
@@ -106,7 +97,7 @@ class PositionTemplateListView(ELTAuthenticatedAPIView):
if not tenant_uuid:
return Response({'Code': 400, 'Msg': 'TenantUUID 必填', 'Data': None}, status=400)
templates = PositionTemplate.objects.filter(TenantUUID=tenant_uuid, TemplateStatus=1)
templates = PositionManager.GetTemplatesForTenant(tenant_uuid)
serializer = PositionTemplateSerializer(templates, many=True)
return Response({'Code': 200, 'Msg': 'OK', 'Data': serializer.data})
@@ -125,15 +116,12 @@ class PositionTemplateCreateView(ELTAuthenticatedAPIView):
except Tenant.DoesNotExist:
return Response({'Code': 404, 'Msg': '租户不存在', 'Data': None}, status=404)
template = PositionTemplate(
PositionTemplateUUID=uuid.uuid4().bytes,
TenantUUID=tenant,
TemplateName=data['TemplateName'],
TemplateCode=data.get('TemplateCode', ''),
TemplateStatus=1,
template = PositionManager.CreatePositionTemplate(
data['TemplateName'],
tenant.TenantUUID,
Code=data.get('TemplateCode', ''),
TemplateDesc=data.get('TemplateDesc', ''),
)
template.save()
return Response({'Code': 200, 'Msg': '创建成功', 'Data': PositionTemplateSerializer(template).data})
@@ -146,17 +134,14 @@ class PositionTemplateUpdateView(ELTAuthenticatedAPIView):
return Response({'Code': 400, 'Msg': serializer.errors, 'Data': None}, status=400)
data = serializer.validated_data
try:
template = PositionTemplate.objects.get(PositionTemplateUUID=data['PositionTemplateUUID'])
except PositionTemplate.DoesNotExist:
template = PositionManager.GetPositionTemplateByUUID(data['PositionTemplateUUID'])
if template is None:
return Response({'Code': 404, 'Msg': '岗位模板不存在', 'Data': None}, status=404)
for field in ('TemplateName', 'TemplateCode', 'TemplateStatus', 'TemplateDesc'):
if field in data:
setattr(template, field, data[field])
import datetime
template.UpdateTime = datetime.datetime.utcnow()
template.save(update_fields=[f for f in data if f != 'PositionTemplateUUID'] + ['UpdateTime'])
template = PositionManager.UpdatePositionTemplate(
data['PositionTemplateUUID'],
**{f: data[f] for f in ('TemplateName', 'TemplateCode', 'TemplateStatus', 'TemplateDesc') if f in data},
)
return Response({'Code': 200, 'Msg': '更新成功', 'Data': PositionTemplateSerializer(template).data})
@@ -168,15 +153,8 @@ class PositionTemplateDeleteView(ELTAuthenticatedAPIView):
if not template_uuid:
return Response({'Code': 400, 'Msg': 'PositionTemplateUUID 必填', 'Data': None}, status=400)
try:
template = PositionTemplate.objects.get(PositionTemplateUUID=template_uuid)
except PositionTemplate.DoesNotExist:
if not PositionManager.DeletePositionTemplate(template_uuid):
return Response({'Code': 404, 'Msg': '岗位模板不存在', 'Data': None}, status=404)
template.TemplateStatus = 0
import datetime
template.UpdateTime = datetime.datetime.utcnow()
template.save(update_fields=['TemplateStatus', 'UpdateTime'])
return Response({'Code': 200, 'Msg': '删除成功', 'Data': None})
@@ -198,12 +176,7 @@ class PositionTemplatePermAssignView(ELTAuthenticatedAPIView):
if existing:
return Response({'Code': 409, 'Msg': '关联已存在', 'Data': PositionTemplatePermissionSerializer(existing).data})
ptp = PositionTemplatePermission(
PTPermUUID=uuid.uuid4().bytes,
PositionTemplateUUID=data['PositionTemplateUUID'],
PermUUID=data['PermUUID'],
)
ptp.save()
ptp = PositionManager.AssignPermToTemplate(data['PositionTemplateUUID'], data['PermUUID'])
return Response({'Code': 200, 'Msg': '关联成功', 'Data': PositionTemplatePermissionSerializer(ptp).data})
@@ -216,11 +189,7 @@ class PositionTemplatePermRemoveView(ELTAuthenticatedAPIView):
return Response({'Code': 400, 'Msg': serializer.errors, 'Data': None}, status=400)
data = serializer.validated_data
deleted, _ = PositionTemplatePermission.objects.filter(
PositionTemplateUUID=data['PositionTemplateUUID'],
PermUUID=data['PermUUID'],
).delete()
if deleted > 0:
if PositionManager.RemovePermFromTemplate(data['PositionTemplateUUID'], data['PermUUID']):
return Response({'Code': 200, 'Msg': '移除成功', 'Data': None})
return Response({'Code': 404, 'Msg': '关联不存在', 'Data': None})
@@ -233,11 +202,7 @@ class PositionTemplatePermsView(ELTAuthenticatedAPIView):
if not template_uuid:
return Response({'Code': 400, 'Msg': 'PositionTemplateUUID 必填', 'Data': None}, status=400)
from gvsds.apps.gerp.models import Permission
ptp_uuids = PositionTemplatePermission.objects.filter(
PositionTemplateUUID=template_uuid
).values_list('PermUUID', flat=True)
perms = Permission.objects.filter(PermUUID__in=ptp_uuids)
from gvsds.apps.gerp.serializers import PermissionSerializer
perms = PositionManager.GetPermsForTemplate(template_uuid)
serializer = PermissionSerializer(perms, many=True)
return Response({'Code': 200, 'Msg': 'OK', 'Data': serializer.data})
+167 -2
View File
@@ -1,10 +1,10 @@
import uuid
from django.utils import timezone as _timezone
from gvsdsdk.models import Role, UserRole, RolePermission, Permission
from gvsdsdk.models import Role, UserRole, RolePermission, Permission, Position, PositionTemplate, PositionTemplatePermission
from gvsdsdk.model_utils import _GetUserModel
# NOTE: 类型注解暂缓——RoleManager 静态方法较多,全量补充注解工作量较大且易引入回归,后续单独迭代处理。
# NOTE: 类型注解暂缓——RoleManager/PositionManager 静态方法较多,全量补充注解工作量较大且易引入回归,后续单独迭代处理。
class RoleManager:
@@ -167,3 +167,168 @@ class RoleManager:
qs = qs.filter(CompanyUUID=CompanyUUID)
return qs.exists()
class PositionManager:
"""职务管理器——提供人事职务标签创建、岗位模板管理"""
# ── 人事职务标签 ──
@staticmethod
def CreatePosition(Name, TenantUUID, Code='', Level=0, **Kwargs):
"""创建人事职务标签(TenantUUID 传 UUIDObj/str/bytes)"""
position = Position(
PositionUUID=uuid.uuid4().bytes,
TenantUUID=TenantUUID,
PositionName=Name,
PositionCode=Code,
PositionLevel=Level,
PositionStatus=1,
PositionDesc=Kwargs.get('PositionDesc', ''),
CreateTime=_timezone.now(),
UpdateTime=_timezone.now(),
)
position.save()
return position
@staticmethod
def GetPositionsForTenant(TenantUUID):
"""获取租户下的所有启用职务"""
return Position.objects.filter(TenantUUID=TenantUUID, PositionStatus=1)
@staticmethod
def GetPositionByUUID(PositionUUID):
"""按 UUID 查询职务(不存在返回 None)"""
return Position.objects.filter(PositionUUID=PositionUUID).first()
@staticmethod
def UpdatePosition(PositionUUID, **Fields):
"""更新职务字段(自动刷新 UpdateTime)
Args:
PositionUUID: 职务 UUID
**Fields: 允许字段 PositionName/PositionCode/PositionLevel/PositionStatus/PositionDesc
Returns:
更新后的 Position 实例;职务不存在返回 None
"""
position = Position.objects.filter(PositionUUID=PositionUUID).first()
if not position:
return None
allowed = ('PositionName', 'PositionCode', 'PositionLevel', 'PositionStatus', 'PositionDesc')
update_fields = []
for key, value in Fields.items():
if key in allowed:
setattr(position, key, value)
update_fields.append(key)
position.UpdateTime = _timezone.now()
update_fields.append('UpdateTime')
if update_fields:
position.save(update_fields=update_fields)
return position
@staticmethod
def DeletePosition(PositionUUID):
"""软删除职务(PositionStatus=0);返回是否命中"""
position = Position.objects.filter(PositionUUID=PositionUUID).first()
if not position:
return False
position.PositionStatus = 0
position.UpdateTime = _timezone.now()
position.save(update_fields=['PositionStatus', 'UpdateTime'])
return True
# ── 岗位模板 ──
@staticmethod
def CreatePositionTemplate(Name, TenantUUID, Code='', **Kwargs):
"""创建岗位模板(TenantUUID 传 UUIDObj/str/bytes)"""
template = PositionTemplate(
PositionTemplateUUID=uuid.uuid4().bytes,
TenantUUID=TenantUUID,
TemplateName=Name,
TemplateCode=Code,
TemplateStatus=1,
TemplateDesc=Kwargs.get('TemplateDesc', ''),
CreateTime=_timezone.now(),
UpdateTime=_timezone.now(),
)
template.save()
return template
@staticmethod
def GetTemplatesForTenant(TenantUUID):
"""获取租户下的所有启用岗位模板"""
return PositionTemplate.objects.filter(TenantUUID=TenantUUID, TemplateStatus=1)
@staticmethod
def GetPositionTemplateByUUID(PositionTemplateUUID):
"""按 UUID 查询岗位模板(不存在返回 None)"""
return PositionTemplate.objects.filter(PositionTemplateUUID=PositionTemplateUUID).first()
@staticmethod
def UpdatePositionTemplate(PositionTemplateUUID, **Fields):
"""更新岗位模板字段(自动刷新 UpdateTime)
Args:
PositionTemplateUUID: 岗位模板 UUID
**Fields: 允许字段 TemplateName/TemplateCode/TemplateStatus/TemplateDesc
Returns:
更新后的 PositionTemplate 实例;模板不存在返回 None
"""
template = PositionTemplate.objects.filter(PositionTemplateUUID=PositionTemplateUUID).first()
if not template:
return None
allowed = ('TemplateName', 'TemplateCode', 'TemplateStatus', 'TemplateDesc')
update_fields = []
for key, value in Fields.items():
if key in allowed:
setattr(template, key, value)
update_fields.append(key)
template.UpdateTime = _timezone.now()
update_fields.append('UpdateTime')
if update_fields:
template.save(update_fields=update_fields)
return template
@staticmethod
def DeletePositionTemplate(PositionTemplateUUID):
"""软删除岗位模板(TemplateStatus=0);返回是否命中"""
template = PositionTemplate.objects.filter(PositionTemplateUUID=PositionTemplateUUID).first()
if not template:
return False
template.TemplateStatus = 0
template.UpdateTime = _timezone.now()
template.save(update_fields=['TemplateStatus', 'UpdateTime'])
return True
# ── 岗位模板权限关联 ──
@staticmethod
def AssignPermToTemplate(TemplateUUID, PermUUID):
"""为岗位模板关联权限"""
ptp = PositionTemplatePermission(
PTPermUUID=uuid.uuid4().bytes,
PositionTemplateUUID=TemplateUUID,
PermUUID=PermUUID,
CreateTime=_timezone.now(),
)
ptp.save()
return ptp
@staticmethod
def RemovePermFromTemplate(TemplateUUID, PermUUID):
"""移除岗位模板与权限的关联;返回是否命中"""
deleted, _ = PositionTemplatePermission.objects.filter(
PositionTemplateUUID=TemplateUUID, PermUUID=PermUUID
).delete()
return deleted > 0
@staticmethod
def GetPermsForTemplate(TemplateUUID):
"""获取岗位模板关联的所有启用权限"""
perm_uuids = PositionTemplatePermission.objects.filter(
PositionTemplateUUID=TemplateUUID
).values_list('PermUUID', flat=True)
return Permission.objects.filter(PermUUID__in=perm_uuids, PermStatus=1)