from django.contrib.auth import get_user_model from django.test import TestCase from datetime import date from common.models import Role, Thematic, UserConfig, UserThematics from contracts.models import Company, CompanyTeam, Contract from home.models import HomeWidget, HomeWidgetConditionGroup, HomeWidgetCondition class HomeWidgetConditionTests(TestCase): def setUp(self): User = get_user_model() self.user = User.objects.create_user('testuser', password='pass') self.user_config = UserConfig.objects.create(user=self.user, is_intern=True) self.widget = HomeWidget.objects.create(widget_code='intervention_stats') self.group = HomeWidgetConditionGroup.objects.create( widget=self.widget, label='Test Group', order=1, priority=10 ) # Role self.role_admin, _ = Role.objects.get_or_create(name='admin') self.role_tech, _ = Role.objects.get_or_create(name='technician') # Team 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) # Contract self.contract_a = Contract.objects.create( company=self.company, contract_number='C-001', start_date=date(2026, 1, 1), end_date=date(2026, 12, 31) ) self.contract_b = Contract.objects.create( company=self.company, contract_number='C-002', start_date=date(2026, 1, 1), end_date=date(2026, 12, 31) ) # Thematic self.thematic_a = Thematic.objects.create(code='THEME-A', name_fr='Thema A', name_nl='Thema A') self.thematic_b = Thematic.objects.create(code='THEME-B', name_fr='Thema B', name_nl='Thema B') def test_role_condition_evaluation(self): # 1. Non-negated: User has role -> True self.user_config.roles.add(self.role_admin) cond = HomeWidgetCondition.objects.create( group=self.group, condition_type='role', role=self.role_admin, is_negated=False ) self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) # User does not have role -> False cond.role = self.role_tech cond.save() self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # 2. Negated: User has role -> False cond.role = self.role_admin cond.is_negated = True cond.save() self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # User does not have role -> True cond.role = self.role_tech self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) def test_team_condition_evaluation(self): # 1. Non-negated: User team matches -> True cond = HomeWidgetCondition.objects.create( group=self.group, condition_type='team', team=self.team_a, is_negated=False ) self.assertTrue(cond.evaluate(self.user_config, self.team_a, Contract.objects.none())) # User team does not match -> False self.assertFalse(cond.evaluate(self.user_config, self.team_b, Contract.objects.none())) self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # 2. Negated: User team matches -> False cond.is_negated = True cond.save() self.assertFalse(cond.evaluate(self.user_config, self.team_a, Contract.objects.none())) # User team does not match -> True self.assertTrue(cond.evaluate(self.user_config, self.team_b, Contract.objects.none())) self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) def test_contract_condition_evaluation(self): # 1. Non-negated: User has contract -> True cond = HomeWidgetCondition.objects.create( group=self.group, condition_type='contract', contract=self.contract_a, is_negated=False ) user_contracts = Contract.objects.filter(id=self.contract_a.id) self.assertTrue(cond.evaluate(self.user_config, None, user_contracts)) # User does not have contract -> False other_contracts = Contract.objects.filter(id=self.contract_b.id) self.assertFalse(cond.evaluate(self.user_config, None, other_contracts)) # 2. Negated: User has contract -> False cond.is_negated = True cond.save() self.assertFalse(cond.evaluate(self.user_config, None, user_contracts)) # User does not have contract -> True self.assertTrue(cond.evaluate(self.user_config, None, other_contracts)) def test_thematic_condition_evaluation(self): # 1. Non-negated: User has thematic -> True UserThematics.objects.create(user_config=self.user_config, thematic=self.thematic_a) cond = HomeWidgetCondition.objects.create( group=self.group, condition_type='thematic', thematic=self.thematic_a, is_negated=False ) self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) # User does not have thematic -> False cond.thematic = self.thematic_b cond.save() self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # 2. Negated: User has thematic -> False cond.thematic = self.thematic_a cond.is_negated = True cond.save() self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # User does not have thematic -> True cond.thematic = self.thematic_b self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) def test_is_intern_condition_evaluation(self): # 1. Non-negated: matches -> True cond = HomeWidgetCondition.objects.create( group=self.group, condition_type='is_intern', is_intern=True, is_negated=False ) self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) # Does not match -> False cond.is_intern = False cond.save() self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # 2. Negated: matches -> False cond.is_intern = True cond.is_negated = True cond.save() self.assertFalse(cond.evaluate(self.user_config, None, Contract.objects.none())) # Does not match -> True cond.is_intern = False self.assertTrue(cond.evaluate(self.user_config, None, Contract.objects.none())) def test_condition_summary_and_string_representation(self): cond = HomeWidgetCondition.objects.create( group=self.group, condition_type='role', role=self.role_admin, is_negated=False ) self.assertEqual(str(cond), "Role: admin") self.assertEqual(self.group.get_summary(), "role=admin") cond.is_negated = True cond.save() self.assertEqual(str(cond), "NOT Role: admin") self.assertEqual(self.group.get_summary(), "not(role=admin)") class HomeIndexViewTests(TestCase): def test_home_index_inspector_link(self): from django.urls import reverse from django.contrib.auth import get_user_model from common.models import Role, UserConfig User = get_user_model() user = User.objects.create_user('inspector_user', password='pass') user_config = UserConfig.objects.create(user=user) inspector_role, _ = Role.objects.get_or_create(name='inspector') user_config.roles.add(inspector_role) self.client.force_login(user) response = self.client.get(reverse('home:index')) self.assertEqual(response.status_code, 200) self.assertContains(response, reverse('inspections:quick_inspection_map')) self.assertNotContains(response, 'data-bs-target="#newInspectionModal"') def test_home_index_unread_notifications_banner(self): from django.urls import reverse from django.contrib.auth import get_user_model from common.models import UserConfig from notifications.models import Notification, NotificationRecipient User = get_user_model() user = User.objects.create_user('notif_user', password='pass') UserConfig.objects.create(user=user) self.client.force_login(user) # 1. No unread notifications -> banner not shown response = self.client.get(reverse('home:index')) self.assertEqual(response.status_code, 200) self.assertNotContains(response, 'id="home-unread-notifications-alert"') # 2. Add unread notification -> banner shown with count notif = Notification.objects.create(title="Test notification") NotificationRecipient.objects.create(notification=notif, user=user) response = self.client.get(reverse('home:index')) self.assertEqual(response.status_code, 200) self.assertContains(response, 'id="home-unread-notifications-alert"') self.assertContains(response, 'Vous avez 1 notification non lue.') def test_home_index_intervention_on_pause_widget(self): from django.urls import reverse from django.contrib.auth import get_user_model from common.models import UserConfig from home.models import HomeWidget User = get_user_model() user = User.objects.create_user('pause_widget_user', password='pass') UserConfig.objects.create(user=user) self.client.force_login(user) # Create the widget HomeWidget.objects.create(widget_code='intervention_on_pause') response = self.client.get(reverse('home:index'), HTTP_ACCEPT_LANGUAGE='fr') self.assertEqual(response.status_code, 200) self.assertContains(response, 'Interventions en pause') self.assertContains(response, 'status=on_pause') class HomeWidgetAdminTests(TestCase): def setUp(self): from django.contrib.admin.sites import AdminSite from home.admin import HomeWidgetAdmin self.site = AdminSite() self.admin = HomeWidgetAdmin(HomeWidget, self.site) self.widget = HomeWidget.objects.create(widget_code='intervention_stats') def test_conditions_overview_no_groups(self): html = self.admin.conditions_overview(self.widget) self.assertIn('Aucun groupe — visible pour tous', html) def test_conditions_overview_with_groups(self): group = HomeWidgetConditionGroup.objects.create( widget=self.widget, label='Group 1', order=1, priority=1 ) html = self.admin.conditions_overview(self.widget) self.assertIn('Group 1', html)