from django.test import TestCase, Client from django.contrib.auth import get_user_model from django.utils import timezone from django.urls import reverse import json from contracts.models import Company, CompanyTeam, CompanyMember, CompanyMemberHistory from common.models import UserConfig, Role User = get_user_model() class CompanyMemberTeamsTests(TestCase): def setUp(self): # Create user and configuration self.user = User.objects.create_user(username="testuser", password="password123") self.user_config = UserConfig.objects.create(user=self.user, is_intern=True) # Create company and teams self.company = Company.objects.create(name="Test Company") self.team1 = CompanyTeam.objects.create(name="Team Alpha", company=self.company) self.team2 = CompanyTeam.objects.create(name="Team Beta", company=self.company) # Create member self.member = CompanyMember.objects.create( name="Jean Dupont", user=self.user ) def test_assign_multiple_teams(self): """Test that a member can be assigned to multiple teams and history tracks it.""" today = timezone.now().date() # Add to Team 1 self.member.teams.add(self.team1) self.assertEqual(self.member.teams.count(), 1) # Verify history entry created histories = CompanyMemberHistory.objects.filter(member=self.member, team=self.team1) self.assertEqual(histories.count(), 1) self.assertEqual(histories.first().join_date, today) self.assertIsNone(histories.first().leave_date) # Add to Team 2 self.member.teams.add(self.team2) self.assertEqual(self.member.teams.count(), 2) # Verify history for Team 2 histories_team2 = CompanyMemberHistory.objects.filter(member=self.member, team=self.team2) self.assertEqual(histories_team2.count(), 1) self.assertEqual(histories_team2.first().join_date, today) self.assertIsNone(histories_team2.first().leave_date) def test_remove_team(self): """Test that removing a team closes the history period.""" today = timezone.now().date() self.member.teams.add(self.team1) # Remove from Team 1 self.member.teams.remove(self.team1) self.assertEqual(self.member.teams.count(), 0) # Verify history leave_date updated history = CompanyMemberHistory.objects.get(member=self.member, team=self.team1) self.assertEqual(history.leave_date, today) def test_clear_teams(self): """Test that clearing teams closes all active history periods.""" today = timezone.now().date() self.member.teams.add(self.team1) self.member.teams.add(self.team2) # Clear teams self.member.teams.clear() self.assertEqual(self.member.teams.count(), 0) # Verify history leave_date updated for all h1 = CompanyMemberHistory.objects.get(member=self.member, team=self.team1) h2 = CompanyMemberHistory.objects.get(member=self.member, team=self.team2) self.assertEqual(h1.leave_date, today) self.assertEqual(h2.leave_date, today) class TeamViewsAjaxTests(TestCase): def setUp(self): self.client = Client() self.user = User.objects.create_user(username="adminuser", password="password") self.user_config = UserConfig.objects.create(user=self.user, is_intern=True) # Give admin role to bypass permission denials self.admin_role, _ = Role.objects.get_or_create(name="admin") self.user_config.roles.add(self.admin_role) self.client.login(username="adminuser", password="password") self.company = Company.objects.create(name="Test Company") self.team_a = CompanyTeam.objects.create(name="Team A", company=self.company) self.team_b = CompanyTeam.objects.create(name="Team B", company=self.company) self.member = CompanyMember.objects.create(name="Tech A", user=self.user) self.member.teams.add(self.team_a) def test_teams_move_member_transfer(self): """Test moving a member transfers them (removes old, adds new).""" url = reverse('contracts:teams_move_member', args=[self.member.id]) payload = { 'old_team_id': self.team_a.id, 'team_id': self.team_b.id } response = self.client.post( url, data=json.dumps(payload), content_type='application/json' ) self.assertEqual(response.status_code, 200) self.member.refresh_from_db() # Should only belong to Team B now self.assertEqual(list(self.member.teams.all()), [self.team_b]) # Verify history was updated today = timezone.now().date() h_old = CompanyMemberHistory.objects.get(member=self.member, team=self.team_a) self.assertEqual(h_old.leave_date, today) h_new = CompanyMemberHistory.objects.get(member=self.member, team=self.team_b) self.assertEqual(h_new.join_date, today) self.assertIsNone(h_new.leave_date) def test_teams_update_member_modal(self): """Test updating a member via modal view with transfer.""" url = reverse('contracts:teams_update_member', args=[self.member.id]) payload = { 'name': 'Tech A Modified', 'old_team_id': self.team_a.id, 'team_id': self.team_b.id } response = self.client.post( url, data=json.dumps(payload), content_type='application/json' ) self.assertEqual(response.status_code, 200) self.member.refresh_from_db() self.assertEqual(self.member.name, 'Tech A Modified') self.assertEqual(list(self.member.teams.all()), [self.team_b]) def test_teams_create_member_different_company_allowed_for_team_company(self): """Test that a non-admin user can add a member belonging to the target team's company, even if different from user's company.""" from django.contrib.auth.models import User from common.models import UserConfig, Role from contracts.models import Company, CompanyTeam, CompanyMember, UserCompanyTeamAccess # Create user of Company A other_user = User.objects.create_user(username="otheruser", password="password") company_a = Company.objects.create(name="Company A") other_user_config = UserConfig.objects.create(user=other_user, company=company_a) # Create team belonging to Company B company_b = Company.objects.create(name="Company B") team_b = CompanyTeam.objects.create(name="Team Company B", company=company_b) # Grant user edit permission on team_b UserCompanyTeamAccess.objects.create( user_config=other_user_config, team=team_b, can_view=True, can_edit=True ) # Create target user to add, belonging to Company B target_user = User.objects.create_user(username="targetuser", password="password") UserConfig.objects.create(user=target_user, company=company_b) # Login other_user self.client.logout() self.client.login(username="otheruser", password="password") # Call teams_create_member url = reverse('contracts:teams_create_member') payload = { 'name': 'New Target Member', 'user_id': target_user.id, 'team_id': team_b.id } response = self.client.post( url, data=json.dumps(payload), content_type='application/json' ) self.assertEqual(response.status_code, 200) # Verify member was created and added to team_b member = CompanyMember.objects.get(user=target_user) self.assertEqual(member.name, 'New Target Member') self.assertIn(team_b, member.teams.all())