160 lines
5.2 KiB
Python
160 lines
5.2 KiB
Python
from decimal import Decimal
|
|
|
|
from rest_framework import serializers
|
|
|
|
from apps.notifications.services import notify_workspace_membership_added
|
|
from apps.users.models import User
|
|
from core.serializers.base import BaseModelSerializer
|
|
from apps.workspaces.models import PriceUnit, Workspace, WorkspaceMembership, WorkspaceUserRate
|
|
from core.serializers.mini import UserMiniSerializer
|
|
|
|
|
|
class WorkspaceMemberInputSerializer(serializers.Serializer):
|
|
user_id = serializers.UUIDField()
|
|
role = serializers.ChoiceField(choices=WorkspaceMembership.Role.choices, default=WorkspaceMembership.Role.MEMBER)
|
|
|
|
|
|
class WorkspaceSerializer(BaseModelSerializer):
|
|
members = WorkspaceMemberInputSerializer(many=True, write_only=True, required=False)
|
|
my_role = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = Workspace
|
|
fields = BaseModelSerializer.Meta.fields + (
|
|
"name",
|
|
"description",
|
|
"owner",
|
|
"my_role",
|
|
"members",
|
|
)
|
|
read_only_fields = BaseModelSerializer.Meta.fields + (
|
|
"owner",
|
|
)
|
|
|
|
def get_my_role(self, obj):
|
|
membership = WorkspaceMembership.objects.filter(
|
|
workspace=obj,
|
|
user=self.context["request"].user,
|
|
).first()
|
|
return getattr(membership, "role", None)
|
|
|
|
def create(self, validated_data):
|
|
members_data = validated_data.pop('members', [])
|
|
|
|
workspace = super().create(validated_data)
|
|
|
|
memberships_to_create = []
|
|
for member in members_data:
|
|
memberships_to_create.append(
|
|
WorkspaceMembership(
|
|
workspace=workspace,
|
|
user_id=member['user_id'],
|
|
role=member['role'],
|
|
is_active=True
|
|
)
|
|
)
|
|
|
|
if memberships_to_create:
|
|
WorkspaceMembership.objects.bulk_create(memberships_to_create)
|
|
request = self.context.get("request")
|
|
actor = getattr(request, "user", None)
|
|
if actor and actor.is_authenticated:
|
|
users_by_id = User.objects.in_bulk(
|
|
[member["user_id"] for member in members_data]
|
|
)
|
|
for member in members_data:
|
|
recipient = users_by_id.get(member["user_id"])
|
|
if recipient:
|
|
notify_workspace_membership_added(
|
|
actor=actor,
|
|
recipient=recipient,
|
|
workspace=workspace,
|
|
role=member["role"],
|
|
)
|
|
|
|
return workspace
|
|
|
|
|
|
class WorkspaceMembershipSerializer(BaseModelSerializer):
|
|
class Meta:
|
|
model = WorkspaceMembership
|
|
fields = BaseModelSerializer.Meta.fields + (
|
|
"workspace",
|
|
"user",
|
|
"role",
|
|
"is_active",
|
|
)
|
|
|
|
def to_representation(self, instance):
|
|
data = super().to_representation(instance)
|
|
data["user"] = UserMiniSerializer(
|
|
instance.user,
|
|
context=self.context
|
|
).data
|
|
return data
|
|
|
|
|
|
class PriceUnitSerializer(BaseModelSerializer):
|
|
class Meta:
|
|
model = PriceUnit
|
|
fields = BaseModelSerializer.Meta.fields + (
|
|
"code",
|
|
"name",
|
|
"local_name",
|
|
"symbol",
|
|
)
|
|
read_only_fields = fields
|
|
|
|
|
|
class WorkspaceUserRateSerializer(BaseModelSerializer):
|
|
user_details = UserMiniSerializer(source="user", read_only=True)
|
|
price_unit = serializers.SerializerMethodField()
|
|
|
|
class Meta:
|
|
model = WorkspaceUserRate
|
|
fields = BaseModelSerializer.Meta.fields + (
|
|
"workspace",
|
|
"user",
|
|
"user_details",
|
|
"hourly_rate",
|
|
"currency",
|
|
"price_unit",
|
|
"effective_from",
|
|
)
|
|
read_only_fields = fields
|
|
|
|
def get_price_unit(self, obj):
|
|
unit = PriceUnit.objects.filter(code=obj.currency, is_deleted=False).first()
|
|
if not unit:
|
|
return None
|
|
return PriceUnitSerializer(unit, context=self.context).data
|
|
|
|
|
|
class WorkspaceUserRateCreateSerializer(serializers.Serializer):
|
|
workspace_id = serializers.UUIDField()
|
|
user_id = serializers.UUIDField()
|
|
hourly_rate = serializers.DecimalField(max_digits=10, decimal_places=2, min_value=Decimal("0.01"))
|
|
currency = serializers.CharField(max_length=3, default="USD")
|
|
|
|
def validate_currency(self, value):
|
|
code = value.upper()
|
|
if not PriceUnit.objects.filter(code=code, is_deleted=False).exists():
|
|
raise serializers.ValidationError("Selected price unit is invalid.")
|
|
return code
|
|
|
|
|
|
class WorkspaceUserRateUpdateSerializer(serializers.Serializer):
|
|
hourly_rate = serializers.DecimalField(
|
|
max_digits=10,
|
|
decimal_places=2,
|
|
min_value=Decimal("0.01"),
|
|
required=False,
|
|
)
|
|
currency = serializers.CharField(max_length=3, required=False)
|
|
|
|
def validate_currency(self, value):
|
|
code = value.upper()
|
|
if not PriceUnit.objects.filter(code=code, is_deleted=False).exists():
|
|
raise serializers.ValidationError("Selected price unit is invalid.")
|
|
return code
|