diff --git a/gvsds/apps/gerp/views/position.py b/gvsds/apps/gerp/views/position.py index ba55c7ea..5362fdb8 100644 --- a/gvsds/apps/gerp/views/position.py +++ b/gvsds/apps/gerp/views/position.py @@ -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}) diff --git a/gvsdsdk/auth/managers.py b/gvsdsdk/auth/managers.py index 0afffadf..e45dcd39 100644 --- a/gvsdsdk/auth/managers.py +++ b/gvsdsdk/auth/managers.py @@ -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) +