import io from datetime import date from django.test import TestCase, Client from django.contrib.auth.models import User from django.urls import reverse from openpyxl import load_workbook from projects.models import Project, ProjectTag, ProjectTemplate, ProjectTemplateAttribute, ProjectAttributeValue from common.models import UserConfig, Role, Thematic class ConcreteBlocksExportTestCase(TestCase): def setUp(self): # Create standard setup self.user = User.objects.create_user(username="testuser", password="password", email="test@example.com") self.user_config = UserConfig.objects.create(user=self.user, is_intern=True) # Create roles and thematics self.admin_role, _ = Role.objects.get_or_create(name="admin") self.user_config.roles.add(self.admin_role) # Create tags self.nj_tag = ProjectTag.objects.create(name_fr="New-Jersey", slug="new-jersey") self.other_tag = ProjectTag.objects.create(name_fr="Other Tag", slug="other-tag") # Create projects self.project1 = Project.objects.create( name="Project NJ 1", code="P00001", status="in_progress", created_by=self.user, pmo_number=123, osiris_number=456, start_date=date(2026, 1, 1), end_date=date(2026, 6, 1), ) self.project1.tags.add(self.nj_tag) self.project2 = Project.objects.create( name="Project NJ 2", code="P00002", status="planned", created_by=self.user, pmo_number=789, ) self.project2.tags.add(self.nj_tag) self.project_other = Project.objects.create( name="Project Other", code="P00003", status="in_preparation", created_by=self.user, ) self.project_other.tags.add(self.other_tag) # Create templates and attributes self.template = ProjectTemplate.objects.create(name_fr="Template 1", is_active=True) self.project1.templates.add(self.template) self.attr_text = ProjectTemplateAttribute.objects.create( template=self.template, name_fr="Budget", attribute_type="text", order=1 ) self.attr_number = ProjectTemplateAttribute.objects.create( template=self.template, name_fr="Nombre de blocs requis", attribute_type="number", order=2 ) # Create attribute values ProjectAttributeValue.objects.create( project=self.project1, attribute=self.attr_text, value_text="100k€" ) ProjectAttributeValue.objects.create( project=self.project1, attribute=self.attr_number, value_number=15 ) self.client = Client() self.client.login(username="testuser", password="password") def test_export_all_nj_projects(self): url = reverse("maps:projects_new_jersey_export_excel") response = self.client.get(url, HTTP_ACCEPT_LANGUAGE="fr") self.assertEqual(response.status_code, 200) self.assertEqual(response["Content-Type"], "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet") # Load the workbook to verify structure wb = load_workbook(filename=io.BytesIO(response.content)) ws = wb.active self.assertEqual(ws.title, "Projets New-Jersey") # Check headers headers = [cell.value for cell in ws[1]] self.assertIn("Code", headers) self.assertIn("Nom", headers) self.assertIn("Statut", headers) self.assertIn("Numéro PMO", headers) self.assertIn("Template 1 — Budget", headers) self.assertIn("Template 1 — Nombre de blocs requis", headers) # Verify projects exported (project1 and project2 should be present, project_other should not) codes = [ws.cell(row=r, column=1).value for r in range(2, ws.max_row + 1)] self.assertIn("P00001", codes) self.assertIn("P00002", codes) self.assertNotIn("P00003", codes) # Verify values for P00001 for row in range(2, ws.max_row + 1): if ws.cell(row=row, column=1).value == "P00001": # Budget attribute column index budget_idx = headers.index("Template 1 — Budget") + 1 blocks_idx = headers.index("Template 1 — Nombre de blocs requis") + 1 self.assertEqual(ws.cell(row=row, column=budget_idx).value, "100k€") self.assertEqual(ws.cell(row=row, column=blocks_idx).value, "15") def test_export_filtered_nj_projects(self): url = reverse("maps:projects_new_jersey_export_excel") # Filter by search query "P00001" response = self.client.get(url, {"q": "P00001"}, HTTP_ACCEPT_LANGUAGE="fr") self.assertEqual(response.status_code, 200) wb = load_workbook(filename=io.BytesIO(response.content)) ws = wb.active codes = [ws.cell(row=r, column=1).value for r in range(2, ws.max_row + 1)] self.assertIn("P00001", codes) self.assertNotIn("P00002", codes) # Filter by status "planned" response = self.client.get(url, {"status": "planned"}, HTTP_ACCEPT_LANGUAGE="fr") self.assertEqual(response.status_code, 200) wb = load_workbook(filename=io.BytesIO(response.content)) ws = wb.active codes = [ws.cell(row=r, column=1).value for r in range(2, ws.max_row + 1)] self.assertIn("P00002", codes) self.assertNotIn("P00001", codes)