feat(workspaces): add bulk member import endpoints
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
from datetime import timedelta
|
||||
from decimal import Decimal
|
||||
|
||||
from django.utils import timezone
|
||||
from rest_framework.test import APITestCase
|
||||
@@ -7,7 +8,13 @@ from apps.clients.models import Client
|
||||
from apps.projects.models import Project
|
||||
from apps.tags.models import Tag
|
||||
from apps.users.models import User
|
||||
from apps.workspaces.models import Workspace, WorkspaceMembership
|
||||
from apps.workspaces.models import (
|
||||
HourlyRateHistory,
|
||||
PriceUnit,
|
||||
Workspace,
|
||||
WorkspaceMembership,
|
||||
WorkspaceUserRate,
|
||||
)
|
||||
|
||||
|
||||
class WorkspaceCapabilityTests(APITestCase):
|
||||
@@ -298,6 +305,139 @@ class WorkspaceCapabilityTests(APITestCase):
|
||||
self.assertEqual(update_response.status_code, 403)
|
||||
self.assertEqual(delete_response.status_code, 403)
|
||||
|
||||
def test_owner_can_validate_and_commit_member_import_with_rate(self):
|
||||
PriceUnit.objects.create(code="IRT", name="Toman", local_name="Toman", symbol="Toman")
|
||||
target = self._user(21)
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
|
||||
validate_response = self.client.post(
|
||||
"/api/workspace-memberships/import/validate/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"rows": [
|
||||
{
|
||||
"line": 2,
|
||||
"mobile": target.mobile,
|
||||
"role": "member",
|
||||
"hourly_rate": "150000",
|
||||
"currency": "IRT",
|
||||
}
|
||||
],
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(validate_response.status_code, 200)
|
||||
self.assertTrue(validate_response.data["can_commit"])
|
||||
self.assertEqual(validate_response.data["summary"]["valid"], 1)
|
||||
self.assertTrue(validate_response.data["import_token"])
|
||||
|
||||
commit_response = self.client.post(
|
||||
"/api/workspace-memberships/import/commit/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"import_token": validate_response.data["import_token"],
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(commit_response.status_code, 201)
|
||||
self.assertEqual(commit_response.data["created_memberships"], 1)
|
||||
self.assertEqual(commit_response.data["created_or_updated_rates"], 1)
|
||||
self.assertTrue(
|
||||
WorkspaceMembership.objects.filter(
|
||||
workspace=self.workspace,
|
||||
user=target,
|
||||
role=WorkspaceMembership.Role.MEMBER,
|
||||
is_active=True,
|
||||
).exists()
|
||||
)
|
||||
rate = WorkspaceUserRate.objects.get(workspace=self.workspace, user=target)
|
||||
self.assertEqual(rate.hourly_rate, Decimal("150000.00"))
|
||||
self.assertEqual(rate.currency, "IRT")
|
||||
self.assertTrue(
|
||||
HourlyRateHistory.objects.filter(
|
||||
workspace=self.workspace,
|
||||
user=target,
|
||||
hourly_rate=Decimal("150000.00"),
|
||||
currency="IRT",
|
||||
).exists()
|
||||
)
|
||||
|
||||
def test_member_import_rejects_invalid_rows(self):
|
||||
PriceUnit.objects.create(code="USD", name="Dollar", local_name="Dollar", symbol="$")
|
||||
target = self._user(22)
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
|
||||
response = self.client.post(
|
||||
"/api/workspace-memberships/import/validate/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"rows": [
|
||||
{"line": 2, "mobile": "", "role": "member"},
|
||||
{"line": 3, "mobile": "09120000000", "role": "member"},
|
||||
{"line": 4, "mobile": target.mobile, "role": "owner"},
|
||||
{"line": 5, "mobile": target.mobile, "role": "member"},
|
||||
{"line": 6, "mobile": self.member.mobile, "role": "member"},
|
||||
{"line": 7, "mobile": self.guest.mobile, "role": "guest", "hourly_rate": "10"},
|
||||
{"line": 8, "mobile": self.admin.mobile, "role": "admin", "hourly_rate": "0", "currency": "USD"},
|
||||
{"line": 9, "mobile": self.extra_owner.mobile, "role": "guest", "hourly_rate": "10", "currency": "XXX"},
|
||||
],
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertFalse(response.data["can_commit"])
|
||||
self.assertIsNone(response.data["import_token"])
|
||||
self.assertEqual(response.data["summary"]["invalid"], 8)
|
||||
|
||||
def test_admin_import_follows_role_assignment_rules(self):
|
||||
target = self._user(23)
|
||||
self.client.force_authenticate(user=self.admin)
|
||||
|
||||
response = self.client.post(
|
||||
"/api/workspace-memberships/import/validate/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"rows": [{"line": 2, "mobile": target.mobile, "role": "admin"}],
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertFalse(response.data["can_commit"])
|
||||
self.assertIn("permission", response.data["rows"][0]["messages"][0].lower())
|
||||
|
||||
def test_member_cannot_import_workspace_members(self):
|
||||
target = self._user(24)
|
||||
self.client.force_authenticate(user=self.member)
|
||||
|
||||
response = self.client.post(
|
||||
"/api/workspace-memberships/import/validate/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"rows": [{"line": 2, "mobile": target.mobile, "role": "member"}],
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 403)
|
||||
|
||||
def test_import_commit_rejects_expired_token(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
|
||||
response = self.client.post(
|
||||
"/api/workspace-memberships/import/commit/",
|
||||
{
|
||||
"workspace": str(self.workspace.id),
|
||||
"import_token": "invalid-token",
|
||||
},
|
||||
format="json",
|
||||
)
|
||||
|
||||
self.assertEqual(response.status_code, 400)
|
||||
|
||||
def test_admin_can_delete_only_owned_clients_tags_and_projects(self):
|
||||
self.client.force_authenticate(user=self.owner)
|
||||
owner_client_response = self.client.post(
|
||||
|
||||
Reference in New Issue
Block a user