223 lines
7.2 KiB
Python
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
|