feat(pricing): add workspace user rates and price units

This commit is contained in:
2026-04-26 10:19:04 +03:30
parent f960ca8221
commit fadf898486
19 changed files with 731 additions and 266 deletions

View File

@@ -1,9 +1,11 @@
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 Workspace, WorkspaceMembership
from apps.workspaces.models import PriceUnit, Workspace, WorkspaceMembership, WorkspaceUserRate
from core.serializers.mini import UserMiniSerializer
@@ -73,7 +75,7 @@ class WorkspaceSerializer(BaseModelSerializer):
return workspace
class WorkspaceMembershipSerializer(BaseModelSerializer):
class WorkspaceMembershipSerializer(BaseModelSerializer):
class Meta:
model = WorkspaceMembership
fields = BaseModelSerializer.Meta.fields + (
@@ -85,8 +87,73 @@ class WorkspaceMembershipSerializer(BaseModelSerializer):
def to_representation(self, instance):
data = super().to_representation(instance)
data["user"] = UserMiniSerializer(
instance.user,
context=self.context
).data
return data
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