Corp/backend/api/v1/projects/serializers.py
Игорь Надеин 4f6244ab1f
Some checks failed
Deploy production / deploy (push) Failing after 2s
Fix CORP runtime errors and harden deployment and media access
2026-09-10 16:40:08 +03:00

223 lines
7.2 KiB
Python

from decimal import Decimal
from django.contrib.auth import get_user_model
from rest_framework import serializers
from commerce.models import SourceSystem
from projects.models import (
Project,
ProjectExternalBinding,
ProjectMembership,
ProjectResource,
ProjectStage,
)
class ProjectSerializer(serializers.ModelSerializer):
manager_name = serializers.SerializerMethodField()
can_manage = serializers.SerializerMethodField()
can_view_finances = serializers.SerializerMethodField()
class Meta:
model = Project
fields = [
"id",
"name",
"description",
"customer",
"manager",
"manager_name",
"status",
"starts_on",
"ends_on",
"created_at",
"updated_at",
"can_manage",
"can_view_finances",
]
read_only_fields = ["created_at", "updated_at"]
extra_kwargs = {
"manager": {"queryset": get_user_model().objects.filter(is_active=True)}
}
def get_manager_name(self, obj) -> str:
return str(obj.manager)
def get_can_manage(self, obj) -> bool:
from projects.permissions import can_manage
return can_manage(self.context["request"].user, obj)
def get_can_view_finances(self, obj) -> bool:
cached = getattr(self, "_can_view_finances", None)
if cached is None:
from finance.payroll.access import can_access_payroll_management
cached = can_access_payroll_management(self.context["request"].user)
self._can_view_finances = cached
return cached
def validate(self, attrs):
start = attrs.get(
"starts_on", self.instance.starts_on if self.instance else None
)
end = attrs.get("ends_on", self.instance.ends_on if self.instance else None)
if start and end and end < start:
raise serializers.ValidationError("Окончание не может быть раньше начала.")
return attrs
class MembershipSerializer(serializers.ModelSerializer):
employee_name = serializers.SerializerMethodField()
class Meta:
model = ProjectMembership
fields = [
"id",
"employee",
"employee_name",
"role",
"planned_percent",
"starts_on",
"ends_on",
]
extra_kwargs = {
"planned_percent": {"min_value": 0, "max_value": 100},
"employee": {"queryset": get_user_model().objects.filter(is_active=True)},
}
def get_employee_name(self, obj):
return str(obj.employee)
def validate(self, attrs):
if (
attrs.get("starts_on")
and attrs.get("ends_on")
and attrs["ends_on"] < attrs["starts_on"]
):
raise serializers.ValidationError("Окончание участия раньше начала.")
return attrs
class StageSerializer(serializers.ModelSerializer):
class Meta:
model = ProjectStage
fields = ["id", "name", "due_on", "done", "position"]
class BindingSerializer(serializers.ModelSerializer):
source_name = serializers.CharField(source="source.name", read_only=True)
class Meta:
model = ProjectExternalBinding
fields = [
"id",
"source",
"source_name",
"object_type",
"external_id",
"external_name",
]
validators = []
class ResourceSerializer(serializers.ModelSerializer):
class Meta:
model = ProjectResource
fields = ["id", "title", "kind", "url"]
def validate(self, attrs):
from urllib.parse import urlsplit
url = urlsplit(attrs["url"])
prefix = {
"task": "/tasks",
"procurement": "/procurement",
"document": "/documents",
}[attrs["kind"]]
if (
url.scheme
or url.netloc
or "\\" in attrs["url"]
or not (url.path == prefix or url.path.startswith(prefix + "/"))
):
raise serializers.ValidationError(
"Укажите внутреннюю ссылку соответствующего раздела портала."
)
return attrs
class AllocationRowSerializer(serializers.Serializer):
project = serializers.IntegerField(min_value=1, required=False, allow_null=True)
activity = serializers.ChoiceField(
choices=["", "department", "training", "support"], default=""
)
percent = serializers.DecimalField(
max_digits=5, decimal_places=2, min_value=Decimal("0.01"), max_value=100
)
class DaySerializer(serializers.Serializer):
date = serializers.DateField()
version = serializers.IntegerField(min_value=0)
status = serializers.ChoiceField(choices=["draft", "confirmed"])
note = serializers.CharField(max_length=2000, allow_blank=True, default="")
allocations = AllocationRowSerializer(many=True, max_length=50)
class DayProjectSerializer(serializers.Serializer):
id = serializers.IntegerField()
name = serializers.CharField()
class DayAllocationResponseSerializer(serializers.Serializer):
project = serializers.IntegerField(allow_null=True)
project_name = serializers.CharField()
activity = serializers.CharField()
percent = serializers.CharField()
class CalendarDayResponseSerializer(serializers.Serializer):
date = serializers.DateField()
status = serializers.ChoiceField(choices=["draft", "confirmed"])
hours = serializers.FloatField(allow_null=True)
hours_source = serializers.CharField()
version = serializers.IntegerField()
class DayResponseSerializer(CalendarDayResponseSerializer):
attendance_changed = serializers.BooleanField()
note = serializers.CharField()
allocations = DayAllocationResponseSerializer(many=True)
projects = DayProjectSerializer(many=True)
class ReminderRequestSerializer(serializers.Serializer):
snooze = serializers.BooleanField(required=False, default=False)
class ReminderResponseSerializer(serializers.Serializer):
date = serializers.DateField(allow_null=True)
class ExternalProjectImportSerializer(serializers.Serializer):
source = serializers.PrimaryKeyRelatedField(queryset=SourceSystem.objects.all())
external_id = serializers.CharField(max_length=255)
name = serializers.CharField(max_length=255)
description = serializers.CharField(max_length=5000, allow_blank=True, default="")
customer = serializers.CharField(max_length=255, allow_blank=True, default="")
manager = serializers.PrimaryKeyRelatedField(
queryset=get_user_model().objects.filter(is_active=True)
)
status = serializers.ChoiceField(choices=Project.Status.choices, default="planned")
starts_on = serializers.DateField(required=False, allow_null=True)
ends_on = serializers.DateField(required=False, allow_null=True)
def validate(self, attrs):
if attrs.get("starts_on") and attrs.get("ends_on"):
if attrs["ends_on"] < attrs["starts_on"]:
raise serializers.ValidationError(
"Окончание не может быть раньше начала."
)
return attrs