feat(projects): add project-specific member rates
This commit is contained in:
@@ -16,9 +16,11 @@ from apps.projects.models import Project
|
||||
from apps.projects.api.serializers import (
|
||||
ProjectSerializer, ProjectCreateSerializer, ProjectUpdateSerializer,
|
||||
ProjectAccessMutationSerializer, ProjectAccessQuerySerializer,
|
||||
ProjectAccessRateMutationSerializer,
|
||||
)
|
||||
from apps.projects.api.permissions import IsProjectMember, IsProjectManager
|
||||
from apps.projects.services.access import (
|
||||
build_project_access_item,
|
||||
build_project_access_items,
|
||||
ensure_workspace_project_access,
|
||||
filter_projects_for_user,
|
||||
@@ -26,6 +28,7 @@ from apps.projects.services.access import (
|
||||
grant_project_accesses,
|
||||
revoke_project_accesses,
|
||||
)
|
||||
from apps.projects.services.rates import get_current_project_user_rate, remove_project_user_rate, upsert_project_user_rate
|
||||
from apps.projects.services.projects import (
|
||||
create_project,
|
||||
update_project,
|
||||
@@ -231,3 +234,54 @@ class ProjectViewSet(ModelViewSet):
|
||||
project_ids=[str(project_id) for project_id in serializer.validated_data["project_ids"]],
|
||||
)
|
||||
return Response({"changed": changed}, status=status.HTTP_200_OK)
|
||||
|
||||
@action(detail=False, methods=["post"], url_path="access/rate")
|
||||
def set_access_rate(self, request):
|
||||
serializer = ProjectAccessRateMutationSerializer(data=request.data)
|
||||
serializer.is_valid(raise_exception=True)
|
||||
|
||||
workspace = get_object_or_404(
|
||||
Workspace,
|
||||
id=serializer.validated_data["workspace"],
|
||||
is_deleted=False,
|
||||
)
|
||||
ensure_workspace_project_access(request.user, workspace)
|
||||
membership = get_access_managed_membership(workspace, str(serializer.validated_data["user"]))
|
||||
project = get_object_or_404(
|
||||
Project,
|
||||
id=serializer.validated_data["project"],
|
||||
workspace=workspace,
|
||||
is_deleted=False,
|
||||
)
|
||||
|
||||
has_access = membership.user.project_accesses.filter(project=project).exists()
|
||||
if not has_access:
|
||||
return Response(
|
||||
{"detail": "Grant project access before setting a project-specific rate."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
removed = serializer.validated_data.get("hourly_rate") is None
|
||||
if removed:
|
||||
remove_project_user_rate(project=project, user=membership.user)
|
||||
else:
|
||||
upsert_project_user_rate(
|
||||
project=project,
|
||||
user=membership.user,
|
||||
hourly_rate=serializer.validated_data["hourly_rate"],
|
||||
currency=serializer.validated_data.get("currency", "USD"),
|
||||
)
|
||||
|
||||
workspace_rate = (
|
||||
workspace.user_rates.filter(user=membership.user, is_deleted=False)
|
||||
.order_by("-effective_from", "-updated_at")
|
||||
.first()
|
||||
)
|
||||
project_rate = get_current_project_user_rate(project=project, user=membership.user)
|
||||
item = build_project_access_item(
|
||||
project=project,
|
||||
has_access=True,
|
||||
workspace_rate=workspace_rate,
|
||||
project_rate=project_rate,
|
||||
)
|
||||
return Response({"removed": removed, "item": item}, status=status.HTTP_200_OK)
|
||||
|
||||
Reference in New Issue
Block a user