def test_siae_multiple_memberships(self): siae1 = SiaeWithMembershipFactory() user = siae1.members.first() self.assertTrue(user.siaemembership_set.get(siae=siae1).is_siae_admin) siae2 = SiaeFactory() siae2.members.add(user) self.assertFalse(user.siaemembership_set.get(siae=siae2).is_siae_admin) siae3 = SiaeFactory() siae3.members.add(user) self.assertFalse(user.siaemembership_set.get(siae=siae3).is_siae_admin) factory = RequestFactory() request = factory.get("/") request.user = user middleware = SessionMiddleware() middleware.process_request(request) request.session[settings.ITOU_SESSION_CURRENT_SIAE_KEY] = siae3.pk request.session.save() with self.assertNumQueries(1): result = get_current_organization_and_perms(request) expected = { "current_prescriber_organization": None, "current_siae": siae3, "user_is_prescriber_org_admin": False, "user_is_siae_admin": False, "user_siae_set": [siae1, siae2, siae3], } self.assertDictEqual(expected, result)
def test_select_siae_form_errors(self): """ Test SelectSiaeForm errors. """ # Missing email and SIRET. post_data = {"kind": Siae.KIND_ACI} form = SelectSiaeForm(data=post_data) form.is_valid() expected_error = _( "Merci de renseigner l'e-mail utilisé par le référent technique ASP" " ou un numéro de SIRET connu de nos services." ) self.assertIn(expected_error, form.errors["__all__"]) # (email, kind) or (siret, kind) does not match any siae. post_data = {"email": "*****@*****.**", "siret": "12345678901234", "kind": Siae.KIND_ACI} form = SelectSiaeForm(data=post_data) form.is_valid() expected_error = _("Votre numéro de SIRET ou votre e-mail nous sont inconnus.") self.assertTrue(form.errors["__all__"][0].startswith(expected_error)) # (email, kind) matches two siaes, (siret, kind) does not match any siae. user_email = "*****@*****.**" SiaeFactory.create_batch(2, kind=Siae.KIND_ACI, auth_email=user_email) post_data = {"email": user_email, "siret": "12345678901234", "kind": Siae.KIND_ACI} form = SelectSiaeForm(data=post_data) form.is_valid() expected_error = _("Votre e-mail est partagé par plusieurs structures") self.assertTrue(form.errors["__all__"][0].startswith(expected_error))
def test_district(self): city_slug = "paris-75" paris_city = City.objects.create(name="Paris", slug=city_slug, department="75", post_codes=["75001"], coords=Point(5, 23)) siae_1 = SiaeFactory(department="75", coords=paris_city.coords, post_code="75001") SiaeFactory(department="75", coords=paris_city.coords, post_code="75002") # Filter on city response = self.client.get(self.url, {"city": city_slug}) self.assertContains( response, "Employeurs solidaires à 25 km du centre de Paris (75)") self.assertContains(response, "<b>2</b> résultats") self.assertContains(response, "Arrondissements de Paris") # Filter on district response = self.client.get(self.url, { "city": city_slug, "districts_75": ["75001"] }) self.assertContains(response, "<b>1</b> résultat") self.assertContains(response, siae_1.display_name)
def test_siae_multiple_memberships(self): siae1 = SiaeWithMembershipFactory() user = siae1.members.first() self.assertTrue(siae1.has_admin(user)) siae2 = SiaeFactory() siae2.members.add(user) self.assertFalse(siae2.has_admin(user)) request = self.go_to_dashboard( user=user, establishment_session_key=settings.ITOU_SESSION_CURRENT_SIAE_KEY, establishment_pk=siae2.pk ) with self.assertNumQueries(1): result = get_current_organization_and_perms(request) expected = self.default_result | { "current_siae": siae2, "user_siaes": [siae1, siae2], "user_is_siae_admin": False, "matomo_custom_variables": OrderedDict( [ ("is_authenticated", "yes"), ("account_type", "employer"), ("account_sub_type", "employer_not_admin"), ] ), } self.assertDictEqual(expected, result)
def test_cleaning(self): """Test dataframe cleaning: rows formatting and validation.""" command = self.command # Perfect data. df = pandas.DataFrame([AiCSVFileMock()]) df = command.clean_df(df) row = df.iloc[0] self.assertTrue(isinstance(row[BIRTHDATE_COL], datetime.datetime)) self.assertTrue( isinstance(row[CONTRACT_STARTDATE_COL], datetime.datetime)) self.assertTrue(row["nir_is_valid"]) self.assertTrue(row["siret_validated_by_asp"]) # Invalid birth date. df = pandas.DataFrame([AiCSVFileMock(**{BIRTHDATE_COL: "1668-11-09"})]) df = command.clean_df(df) row = df.iloc[0] self.assertEqual(row[BIRTHDATE_COL].strftime(DATE_FORMAT), "1968-11-09") self.assertTrue(isinstance(row[BIRTHDATE_COL], datetime.datetime)) # Invalid NIR. df = pandas.DataFrame([AiCSVFileMock(**{NIR_COL: "56987534"})]) df = command.clean_df(df) row = df.iloc[0] self.assertEqual(row[NIR_COL], "") self.assertFalse(row["nir_is_valid"]) # Excluded SIRET from the ASP. siret = "33491197100029" df = pandas.DataFrame([AiCSVFileMock(**{SIRET_COL: siret})]) df = command.clean_df(df) row = df.iloc[0] self.assertEqual(row[SIRET_COL], siret) self.assertFalse(row["siret_validated_by_asp"]) # Employer email. domain = "unenouvellechance.fr" siae = SiaeFactory(auth_email=f"accueil@{domain}", kind=Siae.KIND_AI) df = pandas.DataFrame([ AiCSVFileMock(**{ EMAIL_COL: f"colette@{domain}", SIRET_COL: siae.siret }) ]) df = command.clean_df(df) row = df.iloc[0] self.assertEqual(row[EMAIL_COL], "") # Generic email. domain = "gmail.fr" siae = SiaeFactory(auth_email=f"accueil@{domain}", kind=Siae.KIND_AI) df = pandas.DataFrame( [AiCSVFileMock(**{EMAIL_COL: f"colette@{domain}"})]) df = command.clean_df(df) row = df.iloc[0] self.assertEqual(row[EMAIL_COL], "*****@*****.**")
def test_order_by(self): """ Check SIAE results sorting. Don't test sorting by active members to avoid creating too much data. """ guerande = create_city_guerande() created_siaes = [] # Several job descriptions but no job application. siae = SiaeWithJobsFactory(department="44", coords=guerande.coords, post_code="44350") created_siaes.append(siae) # Many job descriptions and job applications. siae = SiaeWithJobsFactory(department="44", coords=guerande.coords, post_code="44350") JobApplicationFactory(to_siae=siae) created_siaes.append(siae) # Many job descriptions and more job applications than the first one. siae = SiaeWithJobsFactory(department="44", coords=guerande.coords, post_code="44350") JobApplicationFactory(to_siae=siae) JobApplicationFactory(to_siae=siae) created_siaes.append(siae) # No job description and a job application siae = SiaeFactory(department="44", coords=guerande.coords, post_code="44350") JobApplicationFactory(to_siae=siae) created_siaes.append(siae) # No job description, no job application. siae = SiaeFactory(department="44", coords=guerande.coords, post_code="44350") created_siaes.append(siae) # Does not want to receive any job application. siae = SiaeFactory(department="44", coords=guerande.coords, post_code="44350", block_job_applications=True) created_siaes.append(siae) response = self.client.get(self.url, {"city": guerande.slug}) siaes_results = response.context["siaes_page"] for i, siae in enumerate(siaes_results): self.assertEqual(siae.pk, created_siaes[i].pk)
def test_siae_signup(self): """SIAE signup.""" siae = SiaeFactory() url = reverse("signup:siae") response = self.client.get(url) self.assertEqual(response.status_code, 200) post_data = { "first_name": "John", "last_name": "Doe", "email": "*****@*****.**", "siret": siae.siret, "password1": "!*p4ssw0rd123-", "password2": "!*p4ssw0rd123-", } response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) user = get_user_model().objects.get(email=post_data["email"]) self.assertFalse(user.is_job_seeker) self.assertFalse(user.is_prescriber) self.assertTrue(user.is_siae_staff) siae = Siae.active_objects.get(siret=post_data["siret"]) self.assertTrue(user.siaemembership_set.get(siae=siae).is_siae_admin) self.assertEqual(1, siae.members.count())
def test_inactive_siae(self): siae = SiaeFactory(convention__is_active=False) invitation = SentSiaeStaffInvitationFactory(siae=siae) user = SiaeStaffFactory(email=invitation.email) self.client.login(email=user.email, password=DEFAULT_PASSWORD) join_url = reverse("invitations_views:join_siae", kwargs={"invitation_id": invitation.id}) response = self.client.get(join_url, follow=True) self.assertContains(response, escape("Cette structure n'est plus active."))
def test_create_preexisting_siae_outside_of_siren_fails(self): siae = SiaeWithMembershipFactory() user = siae.members.first() self.client.login(username=user.email, password=DEFAULT_PASSWORD) url = reverse("siaes_views:create_siae") response = self.client.get(url) self.assertEqual(response.status_code, 200) preexisting_siae = SiaeFactory() new_siret = preexisting_siae.siret self.assertNotEqual(siae.siren, preexisting_siae.siren) self.assertTrue(Siae.objects.filter(siret=new_siret).exists()) post_data = { "siret": new_siret, "kind": preexisting_siae.kind, "name": "FAMOUS SIAE SUB STRUCTURE", "source": Siae.SOURCE_USER_CREATED, "address_line_1": "2 Rue de Soufflenheim", "city": "Betschdorf", "post_code": "67660", "department": "67", "email": "", "phone": "0610203050", "website": "https://famous-siae.com", "description": "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", } response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 200) expected_message = "Le SIRET doit commencer par le SIREN" self.assertNotContains(response, escape(expected_message)) expected_message = "La structure à laquelle vous souhaitez vous rattacher est déjà" self.assertContains(response, escape(expected_message)) self.assertEqual( Siae.objects.filter(siret=post_data["siret"]).count(), 1)
def test_select_siae_form_priority(self): """ Test SelectSiaeForm priority. """ # Priority is given to SIRET match over email match. user_email = "*****@*****.**" siae1 = SiaeFactory(kind=Siae.KIND_ACI, auth_email=user_email) siae2 = SiaeFactory(kind=Siae.KIND_ACI, auth_email=user_email) siae3 = SiaeWithMembershipFactory(kind=Siae.KIND_ACI, siret="12345678901234") post_data = {"email": user_email, "siret": siae3.siret, "kind": Siae.KIND_ACI} form = SelectSiaeForm(data=post_data) form.is_valid() self.assertEqual(form.selected_siae, siae3) # Priority is given to (siret, kind) when same SIRET is used for 2 SIAEs. siae1 = SiaeWithMembershipFactory(kind=Siae.KIND_ETTI) siae2 = SiaeFactory(kind=Siae.KIND_ACI, siret=siae1.siret) # noqa F841 post_data = {"email": user_email, "siret": siae1.siret, "kind": siae1.kind} form = SelectSiaeForm(data=post_data) form.is_valid() self.assertEqual(form.selected_siae, siae1)
def test_kind(self): city = create_city_saint_andre() SiaeFactory(department="44", coords=city.coords, post_code="44117", kind=Siae.KIND_AI) response = self.client.get(self.url, { "city": city.slug, "kinds": [Siae.KIND_AI] }) self.assertContains(response, "<b>1</b> résultat") response = self.client.get(self.url, { "city": city.slug, "kinds": [Siae.KIND_EI] }) self.assertContains(response, "Aucun résultat")
def test_switch_siae(self): siae = SiaeWithMembershipFactory() user = siae.members.first() self.client.login(username=user.email, password=DEFAULT_PASSWORD) related_siae = SiaeFactory() related_siae.members.add(user) url = reverse("dashboard:index") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["current_siae"], siae) url = reverse("siaes_views:card", kwargs={"siae_id": siae.pk}) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["current_siae"], siae) self.assertEqual(response.context["siae"], siae) url = reverse("dashboard:switch_siae") response = self.client.post(url, data={"siae_id": related_siae.pk}) self.assertEqual(response.status_code, 302) url = reverse("dashboard:index") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["current_siae"], related_siae) url = reverse("siaes_views:card", kwargs={"siae_id": related_siae.pk}) response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["current_siae"], related_siae) self.assertEqual(response.context["siae"], related_siae) url = reverse("siaes_views:configure_jobs") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["current_siae"], related_siae) url = reverse("apply:list_for_siae") response = self.client.get(url) self.assertEqual(response.status_code, 200) self.assertEqual(response.context["current_siae"], related_siae)
def test_can_download_approval_as_pdf(self, mock_can_be_cancelled): """ A user can download an approval only when certain conditions are met: - the job_application.to_siae is subject to eligibility rules, - an approval exists (ie is not in the process of being delivered), - this approval is valid, - the job_application has been accepted. """ job_application = JobApplicationWithApprovalFactory() self.assertTrue(job_application.can_download_approval_as_pdf) # SIAE not subject to eligibility rules. not_eligible_kinds = [ choice[0] for choice in Siae.KIND_CHOICES if choice[0] not in Siae.ELIGIBILITY_REQUIRED_KINDS ] not_eligible_siae = SiaeFactory(kind=not_eligible_kinds[0]) job_application = JobApplicationWithApprovalFactory( to_siae=not_eligible_siae) self.assertFalse(job_application.can_download_approval_as_pdf) # Application is not accepted. job_application = JobApplicationWithApprovalFactory( state=JobApplicationWorkflow.STATE_OBSOLETE) self.assertFalse(job_application.can_download_approval_as_pdf) # Application accepted but without approval. job_application = JobApplicationFactory( state=JobApplicationWorkflow.STATE_ACCEPTED) self.assertFalse(job_application.can_download_approval_as_pdf) # Approval has ended start = datetime.date.today() - relativedelta(years=2) end = start + relativedelta(years=1) - relativedelta(days=1) ended_approval = ApprovalFactory(start_at=start, end_at=end) job_application = JobApplicationWithApprovalFactory( approval=ended_approval) self.assertFalse(job_application.can_download_approval_as_pdf)
def test_siae_multiple_memberships(self): siae1 = SiaeWithMembershipFactory() user = siae1.members.first() self.assertTrue(siae1.has_admin(user)) siae2 = SiaeFactory() siae2.members.add(user) self.assertFalse(siae2.has_admin(user)) siae3 = SiaeFactory() siae3.members.add(user) self.assertFalse(siae3.has_admin(user)) factory = RequestFactory() request = factory.get("/") request.user = user middleware = SessionMiddleware() middleware.process_request(request) request.session[settings.ITOU_SESSION_CURRENT_SIAE_KEY] = siae3.pk request.session.save() with self.assertNumQueries(1): result = get_current_organization_and_perms(request) expected = { "current_prescriber_organization": None, "current_siae": siae3, "user_is_prescriber_org_admin": False, "user_is_siae_admin": False, "user_siae_set": [siae1, siae2, siae3], "matomo_custom_variables": OrderedDict([ ("is_authenticated", "yes"), ("account_type", "employer"), ("account_sub_type", "employer_not_admin"), ]), } self.assertDictEqual(expected, result)
def test_siae_signup_when_two_siaes_have_the_same_siret(self): """SIAE signup using a SIRET shared by two siaes.""" siae1 = SiaeFactory() siae1.name = "FIRST SIAE" siae1.kind = Siae.KIND_ETTI siae1.save() siae2 = SiaeFactory() siae2.name = "SECOND SIAE" siae2.kind = Siae.KIND_ACI siae2.siret = siae1.siret siae2.save() url = reverse("signup:siae") response = self.client.get(url) self.assertEqual(response.status_code, 200) post_data = { "first_name": "John", "last_name": "Doe", "email": "*****@*****.**", "siret": siae1.siret, "password1": "!*p4ssw0rd123-", "password2": "!*p4ssw0rd123-", } response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) user = get_user_model().objects.get(email=post_data["email"]) self.assertFalse(user.is_job_seeker) self.assertFalse(user.is_prescriber) self.assertTrue(user.is_siae_staff) siae1 = Siae.active_objects.get(name=siae1.name) self.assertTrue(user.siaemembership_set.get(siae=siae1).is_siae_admin) self.assertEqual(1, siae1.members.count()) siae2 = Siae.active_objects.get(name=siae2.name) self.assertTrue(user.siaemembership_set.get(siae=siae2).is_siae_admin) self.assertEqual(1, siae2.members.count())
def test_join_an_siae_without_members(self): """ A user joins an SIAE without members. The full "email confirmation process" is tested here. Further Siae's signup tests doesn't have to fully test it again. """ user_first_name = "Jacques" user_email = "*****@*****.**" user_secondary_email = "*****@*****.**" password = "******" siae = SiaeFactory(kind=Siae.KIND_ETTI) self.assertEqual(0, siae.members.count()) token = siae.get_token() with mock.patch("itou.utils.tokens.SiaeSignupTokenGenerator.make_token", return_value=token): url = reverse("signup:select_siae") response = self.client.get(url) self.assertEqual(response.status_code, 200) # Find an SIAE: (siret, kind) matches one SIAE. post_data = {"email": user_email, "siret": siae.siret, "kind": siae.kind} response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) self.assertRedirects(response, reverse("home:hp")) self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] self.assertIn("Un nouvel utilisateur souhaite rejoindre votre structure", email.subject) magic_link = siae.signup_magic_link response = self.client.get(magic_link) self.assertEqual(response.status_code, 200) # No error when opening magic link a second time. response = self.client.get(magic_link) self.assertEqual(response.status_code, 200) # Create user. url = reverse("signup:siae") post_data = { # Hidden fields. "encoded_siae_id": siae.get_encoded_siae_id(), "token": siae.get_token(), # Readonly fields. "siret": siae.siret, "kind": siae.kind, "siae_name": siae.display_name, # Regular fields. "first_name": user_first_name, "last_name": "Doe", "email": user_secondary_email, "password1": password, "password2": password, } response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) self.assertRedirects(response, reverse("account_email_verification_sent")) self.assertFalse(get_user_model().objects.filter(email=user_email).exists()) user = get_user_model().objects.get(email=user_secondary_email) # Check `User` state. self.assertFalse(user.is_job_seeker) self.assertFalse(user.is_prescriber) self.assertTrue(user.is_siae_staff) self.assertTrue(user.is_active) self.assertTrue(siae.has_admin(user)) self.assertEqual(1, siae.members.count()) self.assertEqual(user.first_name, user_first_name) self.assertEqual(user.last_name, post_data["last_name"]) self.assertEqual(user.email, user_secondary_email) # Check `EmailAddress` state. self.assertEqual(user.emailaddress_set.count(), 1) user_email = user.emailaddress_set.first() self.assertFalse(user_email.verified) # Check sent email. self.assertEqual(len(mail.outbox), 2) subjects = [email.subject for email in mail.outbox] self.assertIn("[Action requise] Un nouvel utilisateur souhaite rejoindre votre structure", subjects) self.assertIn("Confirmer l'adresse email pour la Plateforme de l'inclusion", subjects) # Magic link is no longer valid because siae.members.count() has changed. response = self.client.get(magic_link, follow=True) redirect_url, status_code = response.redirect_chain[-1] self.assertEqual(status_code, 302) next_url = reverse("signup:select_siae") self.assertEqual(redirect_url, next_url) self.assertEqual(response.status_code, 200) expected_message = _( "Ce lien d'inscription est invalide ou a expiré. " "Veuillez procéder à une nouvelle inscription." ) self.assertContains(response, escape(expected_message)) # User cannot log in until confirmation. post_data = {"login": user.email, "password": password} url = reverse("account_login") response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse("account_email_verification_sent")) # Confirm email + auto login. confirmation_token = EmailConfirmationHMAC(user_email).key confirm_email_url = reverse("account_confirm_email", kwargs={"key": confirmation_token}) response = self.client.post(confirm_email_url) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse("dashboard:index")) user_email = user.emailaddress_set.first() self.assertTrue(user_email.verified)
def test_find_or_create_job_application__create(self): developer = UserFactory( email=settings.AI_EMPLOYEES_STOCK_DEVELOPER_EMAIL) command = self.command # Employers canceled the job application we created, hence removing the PASS IAE we delivered. # Remove those job applications and deliver a new PASS IAE. nir = getattr(CleanedAiCsvFileMock(), NIR_COL) siret = getattr(CleanedAiCsvFileMock(), SIRET_COL) approval = ApprovalFactory(user__nir=nir) df = pandas.DataFrame([CleanedAiCsvFileMock(**{SIRET_COL: siret})]) job_application = JobApplicationSentBySiaeFactory( to_siae__kind=Siae.KIND_AI, to_siae__siret=siret, state=JobApplicationWorkflow.STATE_CANCELLED, job_seeker=approval.user, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_MANUAL, approval=None, approval_manually_delivered_by=developer, created_at=settings.AI_EMPLOYEES_STOCK_IMPORT_DATE, hiring_start_at=df.iloc[0][CONTRACT_STARTDATE_COL], ) created, new_job_application, cancelled_job_app_deleted = command.find_or_create_job_application( approval=approval, job_seeker=job_application.job_seeker, row=df.iloc[0], approval_manually_delivered_by=developer, ) self.assertTrue(created) self.assertTrue(cancelled_job_app_deleted) # Assert employee records creation is blocked. self.assertNotIn( new_job_application, JobApplication.objects.eligible_as_employee_record( new_job_application.to_siae)) self.assertEqual(new_job_application.approval.pk, approval.pk) self.assertFalse( JobApplication.objects.filter(pk=job_application.pk).exists()) self.assertFalse(new_job_application.can_be_cancelled) self.assertTrue(new_job_application.is_from_ai_stock) self.assertEqual(JobApplication.objects.count(), 1) job_application.job_seeker.delete() # Different contract starting date. nir = getattr(CleanedAiCsvFileMock(), NIR_COL) approval = ApprovalFactory(user__nir=nir) siae = SiaeFactory(kind=Siae.KIND_AI) job_application = JobApplicationFactory( to_siae=siae, sender_siae=siae, job_seeker=approval.user, approval=approval, state=JobApplicationWorkflow.STATE_ACCEPTED, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_MANUAL, approval_manually_delivered_by=developer, created_at=settings.AI_EMPLOYEES_STOCK_IMPORT_DATE, hiring_start_at=datetime.date(2021, 1, 1), ) df = pandas.DataFrame( [CleanedAiCsvFileMock(**{SIRET_COL: siae.siret})]) created, new_job_application, cancelled_job_app_deleted = command.find_or_create_job_application( approval=job_application.approval, job_seeker=job_application.job_seeker, row=df.iloc[0], approval_manually_delivered_by=developer, ) self.assertTrue(created) self.assertNotEqual(job_application.pk, new_job_application.pk) self.assertFalse(cancelled_job_app_deleted) job_application.job_seeker.delete()
def test_remove_ignored_rows(self): command = self.command SiaeFactory(kind=Siae.KIND_AI, siret=getattr(CleanedAiCsvFileMock(), SIRET_COL)) # Ended contracts are removed. df = pandas.DataFrame([ CleanedAiCsvFileMock(), CleanedAiCsvFileMock(**{CONTRACT_ENDDATE_COL: "2020-11-30"}) ]) total_df, filtered_df = command.remove_ignored_rows(df) self.assertEqual(len(total_df), 2) self.assertEqual(len(filtered_df), 1) expected_comment = "Ligne ignorée : contrat terminé." self.assertEqual(total_df.iloc[1][COMMENTS_COL], expected_comment) # Continue even if df.CONTRACT_ENDDATE_COL does not exists. df = pandas.DataFrame([ CleanedAiCsvFileMock(), CleanedAiCsvFileMock(**{CONTRACT_ENDDATE_COL: "2020-11-30"}) ]) df = df.drop(columns=[CONTRACT_ENDDATE_COL]) total_df, filtered_df = command.remove_ignored_rows(df) self.assertEqual(len(total_df), 2) self.assertEqual(len(filtered_df), 2) # SIRET provided by the ASP are removed. df = pandas.DataFrame([ CleanedAiCsvFileMock(), CleanedAiCsvFileMock(**{ SIRET_COL: "33491197100029", "siret_validated_by_asp": False }), ]) total_df, filtered_df = command.remove_ignored_rows(df) self.assertEqual(len(total_df), 2) self.assertEqual(len(filtered_df), 1) expected_comment = "Ligne ignorée : entreprise inexistante communiquée par l'ASP." self.assertEqual(total_df.iloc[1][COMMENTS_COL], expected_comment) # Inexistent structures are removed. df = pandas.DataFrame([ CleanedAiCsvFileMock(), CleanedAiCsvFileMock(**{SIRET_COL: "202020202"}) ]) total_df, filtered_df = command.remove_ignored_rows(df) self.assertEqual(len(total_df), 2) self.assertEqual(len(filtered_df), 1) expected_comment = "Ligne ignorée : entreprise inexistante." self.assertEqual(total_df.iloc[1][COMMENTS_COL], expected_comment) # Rows with approvals are removed. df = pandas.DataFrame([ CleanedAiCsvFileMock(), CleanedAiCsvFileMock(**{APPROVAL_COL: "670929"}) ]) total_df, filtered_df = command.remove_ignored_rows(df) self.assertEqual(len(total_df), 2) self.assertEqual(len(filtered_df), 1) expected_comment = "Ligne ignorée : agrément ou PASS IAE renseigné." self.assertEqual(total_df.iloc[1][COMMENTS_COL], expected_comment)
def test_is_subject_to_eligibility_rules(self): siae = SiaeFactory(kind=Siae.KIND_GEIQ) self.assertFalse(siae.is_subject_to_eligibility_rules) siae = SiaeFactory(kind=Siae.KIND_EI) self.assertTrue(siae.is_subject_to_eligibility_rules)
def test_distance(self): # 3 SIAEs in two departments to test distance and department filtering vannes = create_city_vannes() SIAE_VANNES = "SIAE Vannes" SiaeFactory(name=SIAE_VANNES, department="56", coords=vannes.coords, post_code="56760", kind=Siae.KIND_AI) guerande = create_city_guerande() SIAE_GUERANDE = "SIAE Guérande" SiaeFactory(name=SIAE_GUERANDE, department="44", coords=guerande.coords, post_code="44350", kind=Siae.KIND_AI) saint_andre = create_city_saint_andre() SIAE_SAINT_ANDRE = "SIAE Saint André des Eaux" SiaeFactory(name=SIAE_SAINT_ANDRE, department="44", coords=saint_andre.coords, post_code="44117", kind=Siae.KIND_AI) # 100 km response = self.client.get(self.url, { "city": guerande.slug, "distance": 100 }) self.assertContains(response, "<b>3</b> résultats") self.assertContains(response, SIAE_VANNES.capitalize()) self.assertContains(response, SIAE_GUERANDE.capitalize()) self.assertContains(response, SIAE_SAINT_ANDRE.capitalize()) # 15 km response = self.client.get(self.url, { "city": guerande.slug, "distance": 15 }) self.assertContains(response, "<b>2</b> résultats") self.assertContains(response, SIAE_GUERANDE.capitalize()) self.assertContains(response, SIAE_SAINT_ANDRE.capitalize()) # 100 km and 44 response = self.client.get(self.url, { "city": guerande.slug, "distance": 100, "departments": ["44"] }) self.assertContains(response, "<b>2</b> résultats") self.assertContains(response, SIAE_GUERANDE.capitalize()) self.assertContains(response, SIAE_SAINT_ANDRE.capitalize()) # 100 km and 56 response = self.client.get(self.url, { "city": vannes.slug, "distance": 100, "departments": ["56"] }) self.assertContains(response, "<b>1</b> résultat") self.assertContains(response, SIAE_VANNES.capitalize())
def test_import_data_into_itou(self): developer = UserFactory( email=settings.AI_EMPLOYEES_STOCK_DEVELOPER_EMAIL) CommuneFactory(code=getattr(CleanedAiCsvFileMock, CITY_INSEE_COL)) command = self.command base_data = CleanedAiCsvFileMock() siae = SiaeFactory(siret=getattr(base_data, SIRET_COL), kind=Siae.KIND_AI) # User, approval and job application creation. input_df = pandas.DataFrame([base_data]) output_df = command.import_data_into_itou(df=input_df, to_be_imported_df=input_df) self.assertEqual(User.objects.count(), 2) self.assertEqual(Approval.objects.count(), 1) self.assertEqual(JobApplication.objects.count(), 1) job_seeker = User.objects.filter(is_job_seeker=True).get() self.assertEqual(job_seeker.job_applications.count(), 1) self.assertEqual(job_seeker.approvals.count(), 1) job_seeker.delete() # User, approval and job application retrieval. job_seeker = JobSeekerFactory(nir=getattr(base_data, NIR_COL)) ApprovalFactory(user=job_seeker) JobApplicationFactory( sender_kind=JobApplication.SENDER_KIND_SIAE_STAFF, sender_siae=siae, to_siae=siae, created_at=settings.AI_EMPLOYEES_STOCK_IMPORT_DATE, approval_manually_delivered_by=developer, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_MANUAL, job_seeker=job_seeker, hiring_start_at=getattr(base_data, CONTRACT_STARTDATE_COL), ) input_df = pandas.DataFrame([CleanedAiCsvFileMock()]) output_df = command.import_data_into_itou(df=input_df, to_be_imported_df=input_df) self.assertEqual(User.objects.filter(is_job_seeker=True).count(), 1) self.assertEqual(Approval.objects.count(), 1) self.assertEqual(JobApplication.objects.count(), 1) job_seeker.delete() # Only values to be imported are imported but the whole input data frame # is updated for logging purposes. input_df = pandas.DataFrame([ CleanedAiCsvFileMock(**{CONTRACT_ENDDATE_COL: "2020-05-11" }), # Ended contracts are ignored. CleanedAiCsvFileMock( **{SIRET_COL: "598742121322354"}), # Not existing SIAE. CleanedAiCsvFileMock( **{ NIR_COL: "141062a78200555", EMAIL_COL: "*****@*****.**", BIRTHDATE_COL: datetime.date(1997, 3, 12), }), # Different contract start date. CleanedAiCsvFileMock( **{CONTRACT_STARTDATE_COL: datetime.date(2020, 4, 12)}), CleanedAiCsvFileMock(), ]) input_df = command.add_columns_for_asp(input_df) input_df, to_be_imported_df = command.remove_ignored_rows(input_df) output_df = command.import_data_into_itou( df=input_df, to_be_imported_df=to_be_imported_df) self.assertEqual(User.objects.count(), 3) self.assertEqual(Approval.objects.count(), 2) self.assertEqual(JobApplication.objects.count(), 3) job_seeker = User.objects.get(email=getattr(base_data, EMAIL_COL)) self.assertEqual(job_seeker.job_applications.count(), 2) self.assertEqual(job_seeker.approvals.count(), 1) # Different contract start date. job_seeker = User.objects.get(email="*****@*****.**") self.assertEqual(job_seeker.job_applications.count(), 1) self.assertEqual(job_seeker.approvals.count(), 1) # Ignored rows. for _, row in output_df[:2].iterrows(): self.assertTrue(row[COMMENTS_COL]) self.assertFalse(row[PASS_IAE_NUMBER_COL]) self.assertFalse(row[USER_PK_COL]) for _, row in output_df[2:].iterrows(): job_seeker = User.objects.get(nir=row[NIR_COL]) approval = job_seeker.approvals.first() self.assertEqual(row[PASS_IAE_NUMBER_COL], approval.number) self.assertEqual(row[PASS_IAE_START_DATE_COL], approval.start_at.strftime(DATE_FORMAT)) self.assertEqual(row[PASS_IAE_END_DATE_COL], approval.end_at.strftime(DATE_FORMAT)) self.assertEqual(row[USER_PK_COL], job_seeker.jobseeker_hash_id) self.assertEqual(row[USER_ITOU_EMAIL_COL], job_seeker.email) # Clean job_seeker = User.objects.get(nir=getattr(base_data, NIR_COL)) job_seeker.delete() job_seeker = User.objects.get(email="*****@*****.**") job_seeker.delete() # If transaction: raise and pass. job_seeker = JobSeekerFactory( nir=getattr(CleanedAiCsvFileMock(), NIR_COL)) future_date = datetime.date.today() + relativedelta(months=2) ApprovalFactory(user=job_seeker, start_at=future_date) input_df = pandas.DataFrame([ base_data, CleanedAiCsvFileMock( **{ NIR_COL: "141062a78200555", EMAIL_COL: "*****@*****.**", BIRTHDATE_COL: datetime.date(1997, 3, 12), }), ]) output_df = None output_df = command.import_data_into_itou(df=input_df, to_be_imported_df=input_df) self.assertEqual(len(output_df), 2)
def test_has_members(self): siae1 = SiaeFactory() siae2 = SiaeWithMembershipFactory() self.assertFalse(siae1.has_members) self.assertTrue(siae2.has_members)
def test_join_an_siae_without_members(self): """ A user joins an SIAE without members. The full "email confirmation process" is tested here. Further Siae's signup tests doesn't have to fully test it again. """ user_first_name = "Jacques" user_email = "*****@*****.**" user_secondary_email = "*****@*****.**" siae = SiaeFactory(kind=Siae.KIND_ETTI) self.assertEqual(0, siae.members.count()) token = siae.get_token() with mock.patch( "itou.utils.tokens.SiaeSignupTokenGenerator.make_token", return_value=token): url = reverse("signup:siae_select") response = self.client.get(url) self.assertEqual(response.status_code, 200) # Find an SIAE by SIREN. response = self.client.get(url, {"siren": siae.siret[:9]}) self.assertEqual(response.status_code, 200) # Choose an SIAE between results. post_data = {"siaes": siae.pk} # Pass `siren` in request.GET response = self.client.post(f"{url}?siren={siae.siret[:9]}", data=post_data) self.assertEqual(response.status_code, 302) self.assertRedirects(response, "/") self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] self.assertIn( "Un nouvel utilisateur souhaite rejoindre votre structure", email.subject) magic_link = siae.signup_magic_link response = self.client.get(magic_link) self.assertEqual(response.status_code, 200) # No error when opening magic link a second time. response = self.client.get(magic_link) self.assertEqual(response.status_code, 200) # Create user. url = siae.signup_magic_link post_data = { # Hidden fields "encoded_siae_id": siae.get_encoded_siae_id(), "token": siae.get_token(), # Readonly fields "siret": siae.siret, "kind": siae.kind, "siae_name": siae.display_name, # Regular fields "first_name": user_first_name, "last_name": "Doe", "email": user_secondary_email, "password1": DEFAULT_PASSWORD, "password2": DEFAULT_PASSWORD, } response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) self.assertRedirects(response, reverse("account_email_verification_sent")) self.assertFalse(User.objects.filter(email=user_email).exists()) user = User.objects.get(email=user_secondary_email) # Check `User` state. self.assertFalse(user.is_job_seeker) self.assertFalse(user.is_prescriber) self.assertTrue(user.is_siae_staff) self.assertTrue(user.is_active) self.assertTrue(siae.has_admin(user)) self.assertEqual(1, siae.members.count()) # `username` should be a valid UUID, see `User.generate_unique_username()`. self.assertEqual(user.username, uuid.UUID(user.username, version=4).hex) self.assertEqual(user.first_name, user_first_name) self.assertEqual(user.last_name, post_data["last_name"]) self.assertEqual(user.email, user_secondary_email) # Check `EmailAddress` state. self.assertEqual(user.emailaddress_set.count(), 1) user_email = user.emailaddress_set.first() self.assertFalse(user_email.verified) # Check sent email. self.assertEqual(len(mail.outbox), 2) subjects = [email.subject for email in mail.outbox] self.assertIn( "[Action requise] Un nouvel utilisateur souhaite rejoindre votre structure !", subjects) self.assertIn("Confirmez votre adresse e-mail", subjects) # Magic link is no longer valid because siae.members.count() has changed. response = self.client.get(magic_link, follow=True) redirect_url, status_code = response.redirect_chain[-1] self.assertEqual(status_code, 302) next_url = reverse("signup:siae_select") self.assertEqual(redirect_url, next_url) self.assertEqual(response.status_code, 200) expected_message = ( "Ce lien d'inscription est invalide ou a expiré. " "Veuillez procéder à une nouvelle inscription.") self.assertContains(response, escape(expected_message)) # User cannot log in until confirmation. post_data = {"login": user.email, "password": DEFAULT_PASSWORD} url = reverse("account_login") response = self.client.post(url, data=post_data) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse("account_email_verification_sent")) # Confirm email + auto login. confirmation_token = EmailConfirmationHMAC(user_email).key confirm_email_url = reverse("account_confirm_email", kwargs={"key": confirmation_token}) response = self.client.post(confirm_email_url) self.assertEqual(response.status_code, 302) self.assertEqual(response.url, reverse("welcoming_tour:index")) user_email = user.emailaddress_set.first() self.assertTrue(user_email.verified)