fix(workspaces): return import validation codes
Some checks are pending
Backend CI/CD / test (push) Waiting to run
Backend CI/CD / deploy (push) Blocked by required conditions

This commit is contained in:
2026-06-19 01:48:12 +03:30
parent 95f5e85e44
commit 8c7745c935
2 changed files with 13 additions and 13 deletions

View File

@@ -290,7 +290,7 @@ class WorkspaceMembershipViewSet(ModelViewSet):
"status": "invalid", "status": "invalid",
"action": "none", "action": "none",
"user": None, "user": None,
"messages": [f"Import is limited to {MEMBER_IMPORT_MAX_ROWS} rows."], "messages": ["too_many_rows"],
} }
], ],
} }
@@ -307,40 +307,40 @@ class WorkspaceMembershipViewSet(ModelViewSet):
normalized_rate = "" normalized_rate = ""
if not mobile: if not mobile:
messages.append("Mobile is required.") messages.append("mobile_required")
elif mobile in seen_mobiles: elif mobile in seen_mobiles:
messages.append("This mobile appears more than once in the import file.") messages.append("duplicate_mobile")
else: else:
seen_mobiles.add(mobile) seen_mobiles.add(mobile)
user = User.objects.filter(mobile=mobile).first() user = User.objects.filter(mobile=mobile).first()
if not user: if not user:
messages.append("No user exists with this mobile number.") messages.append("user_not_found")
elif str(user.id) in existing_memberships: elif str(user.id) in existing_memberships:
messages.append("This user is already a member of the workspace.") messages.append("already_member")
if role == WorkspaceMembership.Role.OWNER: if role == WorkspaceMembership.Role.OWNER:
messages.append("Owner role cannot be imported.") messages.append("owner_role_not_allowed")
elif role not in allowed_roles: elif role not in allowed_roles:
messages.append("Role must be admin, member, or guest.") messages.append("invalid_role")
elif not can_assign_workspace_role(request.user, workspace, role): elif not can_assign_workspace_role(request.user, workspace, role):
messages.append("You do not have permission to assign this role.") messages.append("role_permission_denied")
has_rate = bool(hourly_rate_raw) has_rate = bool(hourly_rate_raw)
has_currency = bool(currency) has_currency = bool(currency)
if has_rate != has_currency: if has_rate != has_currency:
messages.append("Hourly rate and currency must be provided together.") messages.append("rate_currency_pair_required")
elif has_rate and has_currency: elif has_rate and has_currency:
try: try:
parsed_rate = Decimal(hourly_rate_raw.replace(",", "")) parsed_rate = Decimal(hourly_rate_raw.replace(",", ""))
if parsed_rate <= Decimal("0"): if parsed_rate <= Decimal("0"):
messages.append("Hourly rate must be greater than zero.") messages.append("hourly_rate_positive")
else: else:
normalized_rate = f"{parsed_rate:.2f}" normalized_rate = f"{parsed_rate:.2f}"
except (InvalidOperation, ValueError): except (InvalidOperation, ValueError):
messages.append("Hourly rate must be a valid number.") messages.append("hourly_rate_invalid")
if not PriceUnit.objects.filter(code=currency, is_deleted=False).exists(): if not PriceUnit.objects.filter(code=currency, is_deleted=False).exists():
messages.append("Currency is invalid.") messages.append("currency_invalid")
row_status = "invalid" if messages else "valid" row_status = "invalid" if messages else "valid"
if messages: if messages:

View File

@@ -407,7 +407,7 @@ class WorkspaceCapabilityTests(APITestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertFalse(response.data["can_commit"]) self.assertFalse(response.data["can_commit"])
self.assertIn("permission", response.data["rows"][0]["messages"][0].lower()) self.assertIn("role_permission_denied", response.data["rows"][0]["messages"])
def test_member_cannot_import_workspace_members(self): def test_member_cannot_import_workspace_members(self):
target = self._user(24) target = self._user(24)