def test_is_valid(self): # Start today, end in 2 years. start_at = datetime.date.today() end_at = start_at + relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(approval.is_valid) # End today. end_at = datetime.date.today() start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(approval.is_valid) # Ended 1 year ago. end_at = datetime.date.today() - relativedelta(years=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertFalse(approval.is_valid) # Ended yesterday. end_at = datetime.date.today() - relativedelta(days=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertFalse(approval.is_valid)
def test_waiting_period(self): # End is tomorrow. end_at = datetime.date.today() + relativedelta(days=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(approval.is_valid) self.assertFalse(approval.waiting_period_has_elapsed) self.assertFalse(approval.is_in_waiting_period) # End is today. end_at = datetime.date.today() start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(approval.is_valid) self.assertFalse(approval.waiting_period_has_elapsed) self.assertFalse(approval.is_in_waiting_period) # End is yesterday. end_at = datetime.date.today() - relativedelta(days=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertFalse(approval.is_valid) self.assertFalse(approval.waiting_period_has_elapsed) self.assertTrue(approval.is_in_waiting_period) # Ended since more than WAITING_PERIOD_YEARS. end_at = datetime.date.today() - relativedelta(years=Approval.WAITING_PERIOD_YEARS, days=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertFalse(approval.is_valid) self.assertTrue(approval.waiting_period_has_elapsed) self.assertFalse(approval.is_in_waiting_period)
def test_valid(self): # Start today, end in 2 years. start_at = datetime.date.today() end_at = start_at + relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(Approval.objects.filter(id=approval.id).valid().exists()) # End today. end_at = datetime.date.today() start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(Approval.objects.filter(id=approval.id).valid().exists()) # Ended 1 year ago. end_at = datetime.date.today() - relativedelta(years=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertFalse(Approval.objects.filter(id=approval.id).valid().exists()) # Ended yesterday. end_at = datetime.date.today() - relativedelta(days=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertFalse(Approval.objects.filter(id=approval.id).valid().exists()) # In the future. start_at = datetime.date.today() + relativedelta(years=2) end_at = start_at + relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) self.assertTrue(Approval.objects.filter(id=approval.id).valid().exists())
def test_get_next_number(self): now = timezone.now().date() current_year = now.strftime("%y") # No pre-existing Approval objects. expected_number = f"99999{current_year}00001" self.assertEqual(Approval.get_next_number(), expected_number) # With pre-existing Approval objects. ApprovalFactory(number=f"99999{current_year}00038", start_at=now) ApprovalFactory(number=f"99999{current_year}00039", start_at=now) ApprovalFactory(number=f"99999{current_year}00040", start_at=now) expected_number = f"99999{current_year}00041" self.assertEqual(Approval.get_next_number(), expected_number) Approval.objects.all().delete() # Date of hiring in the past. date_of_hiring = now - relativedelta(years=3) year = date_of_hiring.strftime("%y") ApprovalFactory(number=f"99999{year}99998", start_at=date_of_hiring) expected_number = f"99999{year}99999" self.assertEqual(Approval.get_next_number(date_of_hiring), expected_number) Approval.objects.all().delete() # Date of hiring in the future. date_of_hiring = now + relativedelta(years=3) year = date_of_hiring.strftime("%y") ApprovalFactory(number=f"99999{year}00020", start_at=date_of_hiring) expected_number = f"99999{year}00021" self.assertEqual(Approval.get_next_number(date_of_hiring), expected_number) Approval.objects.all().delete()
def test_valid_for_approval_model(self): """ Test for Approval model. """ start_at = datetime.date.today() - relativedelta(years=1) end_at = start_at + relativedelta(years=1) ApprovalFactory(start_at=start_at, end_at=end_at) start_at = datetime.date.today() - relativedelta(years=5) end_at = start_at + relativedelta(years=2) ApprovalFactory(start_at=start_at, end_at=end_at) self.assertEqual(2, Approval.objects.count()) self.assertEqual(1, Approval.objects.valid().count())
def test_email_approval_number(self): job_seeker = JobSeekerFactory() approval = ApprovalFactory(user=job_seeker) job_application = JobApplicationSentByAuthorizedPrescriberOrganizationFactory( job_seeker=job_seeker, state=JobApplicationWorkflow.STATE_ACCEPTED, approval=approval, ) accepted_by = job_application.to_siae.members.first() email = job_application.email_approval_number(accepted_by) # To. self.assertIn(accepted_by.email, email.to) self.assertEqual(len(email.to), 1) # Body. self.assertIn(approval.user.get_full_name(), email.subject) self.assertIn(approval.number_with_spaces, email.body) self.assertIn(approval.user.last_name, email.body) self.assertIn(approval.user.first_name, email.body) self.assertIn(approval.user.birthdate.strftime("%d/%m/%Y"), email.body) self.assertIn(job_application.hiring_start_at.strftime("%d/%m/%Y"), email.body) self.assertIn(job_application.hiring_end_at.strftime("%d/%m/%Y"), email.body) self.assertIn(job_application.to_siae.display_name, email.body) self.assertIn(job_application.to_siae.get_kind_display(), email.body) self.assertIn(job_application.to_siae.address_line_1, email.body) self.assertIn(job_application.to_siae.address_line_2, email.body) self.assertIn(job_application.to_siae.post_code, email.body) self.assertIn(job_application.to_siae.city, email.body) self.assertIn(settings.ITOU_EMAIL_CONTACT, email.body)
def test_send_number_by_email(self): job_application = JobApplicationSentByAuthorizedPrescriberOrganizationFactory( state=JobApplicationWorkflow.STATE_PROCESSING) job_application.accept(user=job_application.to_siae.members.first()) approval = ApprovalFactory(job_application=job_application) # Delete `accept` and `accept_trigger_manual_approval` emails. mail.outbox = [] approval.send_number_by_email() self.assertEqual(len(mail.outbox), 1) email = mail.outbox[0] self.assertIn(approval.user.get_full_name(), email.subject) self.assertIn(approval.user.get_full_name(), email.body) self.assertIn(approval.number, email.body)
def test_merge_approvals(self): user = JobSeekerFactory() # Approval. approval = ApprovalFactory(user=user, start_at=datetime.date(2016, 12, 20), end_at=datetime.date(2018, 12, 20)) # PoleEmploiApproval 1. pe_approval_1 = PoleEmploiApprovalFactory( pole_emploi_id=user.pole_emploi_id, birthdate=user.birthdate, start_at=datetime.date(2018, 12, 20), end_at=datetime.date(2020, 12, 20), ) # PoleEmploiApproval 2. # Same `start_at` as PoleEmploiApproval 1. # But `end_at` earlier than PoleEmploiApproval 1. pe_approval_2 = PoleEmploiApprovalFactory( pole_emploi_id=user.pole_emploi_id, birthdate=user.birthdate, start_at=datetime.date(2018, 12, 20), end_at=datetime.date(2019, 12, 19), ) # Check timeline. approvals_wrapper = ApprovalsWrapper(user) self.assertEqual(len(approvals_wrapper.merged_approvals), 3) self.assertEqual(approvals_wrapper.merged_approvals[0], pe_approval_1) self.assertEqual(approvals_wrapper.merged_approvals[1], pe_approval_2) self.assertEqual(approvals_wrapper.merged_approvals[2], approval)
def test_get_or_create_from_valid(self): # With an existing valid `PoleEmploiApproval`. user = JobSeekerFactory() valid_pe_approval = PoleEmploiApprovalFactory( pole_emploi_id=user.pole_emploi_id, birthdate=user.birthdate, number="625741810182A01" ) approvals_wrapper = ApprovalsWrapper(user) approval = Approval.get_or_create_from_valid(approvals_wrapper) self.assertTrue(isinstance(approval, Approval)) self.assertEqual(approval.start_at, valid_pe_approval.start_at) self.assertEqual(approval.end_at, valid_pe_approval.end_at) self.assertEqual(approval.number, valid_pe_approval.number[:12]) self.assertEqual(approval.user, user) self.assertEqual(approval.created_by, None) # With an existing valid `Approval`. user = JobSeekerFactory() valid_approval = ApprovalFactory(user=user, start_at=datetime.date.today() - relativedelta(days=1)) approvals_wrapper = ApprovalsWrapper(user) approval = Approval.get_or_create_from_valid(approvals_wrapper) self.assertTrue(isinstance(approval, Approval)) self.assertEqual(approval, valid_approval)
def test_merge_approvals(self): user = JobSeekerFactory() # Create Approval. start_at = datetime.date.today() - relativedelta(years=4) end_at = start_at + relativedelta(years=2) approval = ApprovalFactory(user=user, start_at=start_at, end_at=end_at) # Create PoleEmploiApproval. start_at = datetime.date.today() end_at = start_at + relativedelta(years=2) pe_approval = PoleEmploiApprovalFactory( pole_emploi_id=user.pole_emploi_id, birthdate=user.birthdate, start_at=start_at, end_at=end_at, ) # Check timeline. self.assertTrue(approval.start_at < pe_approval.start_at) approvals_wrapper = ApprovalsWrapper(user) self.assertEqual(len(approvals_wrapper.merged_approvals), 2) self.assertEqual(approvals_wrapper.merged_approvals[0], pe_approval) self.assertEqual(approvals_wrapper.merged_approvals[1], approval)
def test_apply_as_prescriber_for_approval_in_waiting_period(self): """Apply as prescriber for a job seeker with an approval in waiting period.""" siae = SiaeWithMembershipAndJobsFactory(romes=("N1101", "N1105")) job_seeker = JobSeekerFactory() # Create an approval in waiting period. end_at = datetime.date.today() - relativedelta(days=30) start_at = end_at - relativedelta(years=2) ApprovalFactory(user=job_seeker, start_at=start_at, end_at=end_at) user = PrescriberFactory() self.client.login(username=user.email, password=DEFAULT_PASSWORD) url = reverse("apply:start", kwargs={"siae_pk": siae.pk}) # Follow all redirections… response = self.client.get(url, follow=True) # …until a job seeker has to be determined… self.assertEqual(response.status_code, 200) last_url = response.redirect_chain[-1][0] self.assertEqual(last_url, reverse("apply:step_check_job_seeker_nir", kwargs={"siae_pk": siae.pk})) # …choose one, then follow all redirections… post_data = {"nir": job_seeker.nir, "confirm": 1} response = self.client.post(last_url, data=post_data, follow=True) # …until the expected 403. self.assertEqual(response.status_code, 403) self.assertEqual(response.context["exception"], ApprovalsWrapper.ERROR_CANNOT_OBTAIN_NEW_FOR_PROXY) last_url = response.redirect_chain[-1][0] self.assertEqual(last_url, reverse("apply:step_check_job_seeker_info", kwargs={"siae_pk": siae.pk}))
def test_status_with_valid_approval(self): user = JobSeekerFactory() approval = ApprovalFactory(user=user, start_at=datetime.date.today() - relativedelta(days=1)) approvals_wrapper = ApprovalsWrapper(user) self.assertEqual(approvals_wrapper.status, ApprovalsWrapper.VALID) self.assertTrue(approvals_wrapper.has_valid) self.assertFalse(approvals_wrapper.has_in_waiting_period) self.assertEqual(approvals_wrapper.latest_approval, approval)
def test_status_approval_with_elapsed_waiting_period(self): user = JobSeekerFactory() end_at = datetime.date.today() - relativedelta(years=3) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(user=user, start_at=start_at, end_at=end_at) approvals_wrapper = ApprovalsWrapper(user) self.assertEqual(approvals_wrapper.status, ApprovalsWrapper.WAITING_PERIOD_HAS_ELAPSED) self.assertFalse(approvals_wrapper.has_valid) self.assertFalse(approvals_wrapper.has_in_waiting_period) self.assertEqual(approvals_wrapper.latest_approval, approval)
def test_get_next_number(self): PREFIX = Approval.ASP_ITOU_PREFIX now = timezone.now().date() current_year = now.strftime("%y") # No pre-existing objects. expected_number = f"{PREFIX}{current_year}00001" self.assertEqual(Approval.get_next_number(), expected_number) # With pre-existing objects. ApprovalFactory(number=f"{PREFIX}{current_year}00038", start_at=now) ApprovalFactory(number=f"{PREFIX}{current_year}00039", start_at=now) ApprovalFactory(number=f"{PREFIX}{current_year}00040", start_at=now) expected_number = f"{PREFIX}{current_year}00041" self.assertEqual(Approval.get_next_number(), expected_number) Approval.objects.all().delete() # Date of hiring in the past. hiring_start_at = now - relativedelta(years=3) year = hiring_start_at.strftime("%y") ApprovalFactory(number=f"{PREFIX}{year}99998", start_at=hiring_start_at) expected_number = f"{PREFIX}{year}99999" self.assertEqual(Approval.get_next_number(hiring_start_at), expected_number) Approval.objects.all().delete() # Date of hiring in the future. hiring_start_at = now + relativedelta(years=3) year = hiring_start_at.strftime("%y") ApprovalFactory(number=f"{PREFIX}{year}00020", start_at=hiring_start_at) expected_number = f"{PREFIX}{year}00021" self.assertEqual(Approval.get_next_number(hiring_start_at), expected_number) Approval.objects.all().delete() # With pre-existing Pôle emploi approval. ApprovalFactory(number=f"625741810182", start_at=now) expected_number = f"{PREFIX}{current_year}00001" self.assertEqual(Approval.get_next_number(), expected_number) Approval.objects.all().delete() # With various pre-existing objects. ApprovalFactory(number=f"{PREFIX}{current_year}00222", start_at=now) ApprovalFactory(number=f"625741810182", start_at=now) expected_number = f"{PREFIX}{current_year}00223" self.assertEqual(Approval.get_next_number(), expected_number) Approval.objects.all().delete()
def test_clean(self): approval = ApprovalFactory() approval.start_at = datetime.date.today() approval.end_at = datetime.date.today() - datetime.timedelta(days=365 * 2) with self.assertRaises(ValidationError): approval.save()
def test_is_considered_valid(self): # Valid diagnosis. diagnosis = EligibilityDiagnosisFactory() self.assertTrue(diagnosis.is_considered_valid) # Expired diagnosis. diagnosis = ExpiredEligibilityDiagnosisFactory() self.assertFalse(diagnosis.is_considered_valid) # Expired diagnosis but ongoing PASS IAE. diagnosis = ExpiredEligibilityDiagnosisFactory() ApprovalFactory(user=diagnosis.job_seeker) self.assertTrue(diagnosis.is_considered_valid)
def test_find_or_create_approval__find(self): developer = UserFactory( email=settings.AI_EMPLOYEES_STOCK_DEVELOPER_EMAIL) command = self.command # Existing valid PASS IAE delivered after a job application has been accepted. approval_start_at = datetime.date( 2021, 11, 10) # Approval should start before November 30th. existing_approval = ApprovalFactory(user__nir=getattr( CleanedAiCsvFileMock(), NIR_COL), start_at=approval_start_at) created, expected_approval, _ = command.find_or_create_approval( job_seeker=existing_approval.user, created_by=developer) self.assertFalse(created) self.assertTrue(expected_approval.is_valid) # Make sure no update was made. self.assertEqual(existing_approval.pk, expected_approval.pk) self.assertEqual(existing_approval.start_at, expected_approval.start_at) self.assertEqual(existing_approval.user.pk, expected_approval.user.pk) # Clean existing_approval.user.delete() # PASS IAE created previously by this script. existing_approval = ApprovalFactory( user__nir=getattr(CleanedAiCsvFileMock(), NIR_COL), start_at=datetime.date(2021, 12, 1), created_by=developer, created_at=settings.AI_EMPLOYEES_STOCK_IMPORT_DATE, ) created, expected_approval, _ = command.find_or_create_approval( job_seeker=existing_approval.user, created_by=developer) self.assertFalse(created) self.assertEqual(existing_approval.pk, expected_approval.pk) self.assertTrue(expected_approval.is_valid) # Clean existing_approval.user.delete()
def test_has_valid_approval(self): # Start today, end in 2 years. start_at = datetime.date.today() end_at = start_at + relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) user = approval.user self.assertTrue(user.has_valid_approval()) # End today. end_at = datetime.date.today() start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) user = approval.user self.assertTrue(user.has_valid_approval()) # Ended 1 year ago. end_at = datetime.date.today() - relativedelta(years=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) user = approval.user self.assertFalse(user.has_valid_approval()) # Ended yesterday. end_at = datetime.date.today() - relativedelta(days=1) start_at = end_at - relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) user = approval.user self.assertFalse(user.has_valid_approval()) # In the future. start_at = datetime.date.today() + relativedelta(years=2) end_at = start_at + relativedelta(years=2) approval = ApprovalFactory(start_at=start_at, end_at=end_at) user = approval.user self.assertTrue(user.has_valid_approval())
def test_can_be_deleted(self): job_app = JobApplicationWithApprovalFactory(state=JobApplicationWorkflow.STATE_ACCEPTED) approval = job_app.approval self.assertTrue(approval.can_be_deleted) # An approval exists without a Job Application approval = ApprovalFactory() self.assertFalse(approval.can_be_deleted) job_app.state = JobApplicationWorkflow.STATE_REFUSED job_app.save() self.assertFalse(approval.can_be_deleted) JobApplicationWithApprovalFactory( state=JobApplicationWorkflow.STATE_ACCEPTED, job_seeker=job_app.job_seeker, approval=job_app.approval ) self.assertFalse(approval.can_be_deleted)
def test_send_approval_number_by_email_manually(self): staff_member = UserFactory(is_staff=True) job_seeker = JobSeekerFactory() approval = ApprovalFactory(user=job_seeker) job_application = JobApplicationSentByAuthorizedPrescriberOrganizationFactory( job_seeker=job_seeker, state=JobApplicationWorkflow.STATE_PROCESSING, approval=approval) job_application.accept(user=job_application.to_siae.members.first()) mail.outbox = [] # Delete previous emails. job_application.send_approval_number_by_email_manually( deliverer=staff_member) self.assertTrue(job_application.approval_number_sent_by_email) self.assertIsNotNone(job_application.approval_number_sent_at) self.assertEqual(job_application.approval_delivery_mode, job_application.APPROVAL_DELIVERY_MODE_MANUAL) self.assertEqual(job_application.approval_number_delivered_by, staff_member) self.assertEqual(len(mail.outbox), 1)
def test_when_pole_emploi_approval_has_already_been_imported(self): """ When the PoleEmploiApproval has already been imported, we are redirected to its page """ self.job_application = JobApplicationWithApprovalFactory( state=JobApplicationWorkflow.STATE_ACCEPTED, approval=ApprovalFactory(number=self.pe_approval.number[:12]) ) initial_approval_count = Approval.objects.count() job_seeker = JobSeekerFactory() self.client.login(username=self.siae_user.email, password=DEFAULT_PASSWORD) url = reverse("approvals:pe_approval_create", kwargs={"pe_approval_id": self.pe_approval.id}) params = {"email": job_seeker.email} response = self.client.post(url, params) self.assertEqual(response.status_code, 302) self.assertEqual(Approval.objects.count(), initial_approval_count) messages = list(get_messages(response.wsgi_request)) self.assertEqual(len(messages), 1) self.assertEqual(str(messages[0]), "Cet agrément a déjà été importé.")
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_apply_as_authorized_prescriber_for_approval_in_waiting_period( self): """Apply as authorized prescriber for a job seeker with an approval in waiting period.""" siae = SiaeWithMembershipAndJobsFactory(romes=("N1101", "N1105")) job_seeker = JobSeekerFactory() # Create an approval in waiting period. end_at = datetime.date.today() - relativedelta(days=30) start_at = end_at - relativedelta(years=2) ApprovalFactory(user=job_seeker, start_at=start_at, end_at=end_at) prescriber_organization = PrescriberOrganizationWithMembershipFactory( is_authorized=True) user = prescriber_organization.members.first() self.client.login(username=user.email, password=DEFAULT_PASSWORD) url = reverse("apply:start", kwargs={"siae_pk": siae.pk}) # Follow all redirections… response = self.client.get(url, follow=True) # …until a job seeker has to be determined… self.assertEqual(response.status_code, 200) last_url = response.redirect_chain[-1][0] self.assertEqual( last_url, reverse("apply:step_job_seeker", kwargs={"siae_pk": siae.pk})) # …choose one, then follow all redirections… post_data = {"email": job_seeker.email} response = self.client.post(last_url, data=post_data, follow=True) # …until the eligibility step which should trigger a 200 OK. self.assertEqual(response.status_code, 200) last_url = response.redirect_chain[-1][0] self.assertEqual( last_url, reverse("apply:step_eligibility", kwargs={"siae_pk": siae.pk}))
def test_find_or_create_job_application__find(self): # Find job applications created previously by this script. developer = UserFactory( email=settings.AI_EMPLOYEES_STOCK_DEVELOPER_EMAIL) command = self.command # An approval is mandatory to test employee records creation (FS). approval = ApprovalFactory( user__nir=getattr(CleanedAiCsvFileMock(), NIR_COL)) expected_job_app = JobApplicationSentBySiaeFactory( to_siae__kind=Siae.KIND_AI, state=JobApplicationWorkflow.STATE_ACCEPTED, # Mandatory for FS. job_seeker=approval.user, approval=approval, approval_manually_delivered_by=developer, created_at=settings.AI_EMPLOYEES_STOCK_IMPORT_DATE, hiring_start_at=getattr(CleanedAiCsvFileMock(), CONTRACT_STARTDATE_COL), ) job_seeker = expected_job_app.job_seeker df = pandas.DataFrame([ CleanedAiCsvFileMock(**{SIRET_COL: expected_job_app.to_siae.siret}) ]) created, found_job_application, _ = command.find_or_create_job_application( approval=expected_job_app.approval, job_seeker=job_seeker, row=df.iloc[0], approval_manually_delivered_by=developer, ) self.assertFalse(created) self.assertEqual(expected_job_app.pk, found_job_application.pk) self.assertFalse(found_job_application.can_be_cancelled) # Assert job application has been updated to block employee records creation. self.assertNotIn( found_job_application, JobApplication.objects.eligible_as_employee_record( found_job_application.to_siae))
def test_valid_and_expired_methods(self): """ Test both `has_considered_valid()`, `last_considered_valid()` and `last_expired()` methods. """ # No diagnosis. job_seeker = JobSeekerFactory() has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid(job_seeker=job_seeker) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid(job_seeker=job_seeker) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) self.assertIsNone(last_considered_valid) self.assertIsNone(last_expired) self.assertFalse(has_considered_valid) # Has Itou diagnosis. diagnosis = EligibilityDiagnosisFactory() has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid(job_seeker=diagnosis.job_seeker) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid(job_seeker=diagnosis.job_seeker) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=diagnosis.job_seeker) self.assertEqual(last_considered_valid, diagnosis) self.assertIsNone(last_expired) self.assertTrue(has_considered_valid) # Has a valid PASS IAE but NO diagnosis. approval = ApprovalFactory() job_seeker = approval.user self.assertEqual(0, job_seeker.eligibility_diagnoses.count()) has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid(job_seeker=job_seeker) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid(job_seeker=job_seeker) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) self.assertTrue(has_considered_valid) self.assertIsNone(last_considered_valid) self.assertIsNone(last_expired) # Has valid Pôle emploi diagnosis. job_seeker = JobSeekerFactory() PoleEmploiApprovalFactory(pole_emploi_id=job_seeker.pole_emploi_id, birthdate=job_seeker.birthdate) has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid(job_seeker=job_seeker) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid(job_seeker=job_seeker) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) self.assertTrue(has_considered_valid) self.assertIsNone(last_considered_valid) self.assertIsNone(last_expired) # Has expired Pôle emploi diagnosis. job_seeker = JobSeekerFactory() end_at = datetime.date.today() - relativedelta(years=2) start_at = end_at - relativedelta(years=2) PoleEmploiApprovalFactory( pole_emploi_id=job_seeker.pole_emploi_id, birthdate=job_seeker.birthdate, start_at=start_at, end_at=end_at ) has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid(job_seeker=job_seeker) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid(job_seeker=job_seeker) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) self.assertFalse(has_considered_valid) self.assertIsNone(last_considered_valid) self.assertIsNone(last_expired) # Has expired Itou diagnosis. expired_diagnosis = ExpiredEligibilityDiagnosisFactory() has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid( job_seeker=expired_diagnosis.job_seeker ) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid( job_seeker=expired_diagnosis.job_seeker ) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=expired_diagnosis.job_seeker) self.assertFalse(has_considered_valid) self.assertIsNone(last_considered_valid) self.assertIsNotNone(last_expired) # Has expired Itou diagnosis but has an ongoing PASS IAE. expired_diagnosis = ExpiredEligibilityDiagnosisFactory() ApprovalFactory(user=expired_diagnosis.job_seeker) has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid( job_seeker=expired_diagnosis.job_seeker ) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid( job_seeker=expired_diagnosis.job_seeker ) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=expired_diagnosis.job_seeker) self.assertTrue(has_considered_valid) self.assertEqual(last_considered_valid, expired_diagnosis) self.assertIsNone(last_expired) # Has Itou diagnosis made by an SIAE. siae1 = SiaeWithMembershipFactory() siae2 = SiaeWithMembershipFactory() diagnosis = EligibilityDiagnosisMadeBySiaeFactory(author_siae=siae1) # From `siae1` perspective. has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid( job_seeker=diagnosis.job_seeker, for_siae=siae1 ) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid( job_seeker=diagnosis.job_seeker, for_siae=siae1 ) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=diagnosis.job_seeker, for_siae=siae1) self.assertTrue(has_considered_valid) self.assertEqual(last_considered_valid, diagnosis) self.assertIsNone(last_expired) # From `siae2` perspective. has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid( job_seeker=diagnosis.job_seeker, for_siae=siae2 ) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid( job_seeker=diagnosis.job_seeker, for_siae=siae2 ) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=diagnosis.job_seeker, for_siae=siae2) self.assertFalse(has_considered_valid) self.assertIsNone(last_considered_valid) self.assertIsNone(last_expired) # Has Itou diagnosis made by a prescriber. siae = SiaeWithMembershipFactory() prescriber_diagnosis = EligibilityDiagnosisFactory() # From siae perspective. has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid( job_seeker=prescriber_diagnosis.job_seeker, for_siae=siae ) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid( job_seeker=prescriber_diagnosis.job_seeker, for_siae=siae ) last_expired = EligibilityDiagnosis.objects.last_expired( job_seeker=prescriber_diagnosis.job_seeker, for_siae=siae ) self.assertTrue(has_considered_valid) self.assertEqual(last_considered_valid, prescriber_diagnosis) self.assertIsNone(last_expired) # Has 2 Itou diagnoses: 1 made by an SIAE prior to another one by a prescriber. job_seeker = JobSeekerFactory() siae = SiaeWithMembershipFactory() prescriber_diagnosis = EligibilityDiagnosisFactory(job_seeker=job_seeker) # From `siae` perspective. has_considered_valid = EligibilityDiagnosis.objects.has_considered_valid(job_seeker=job_seeker, for_siae=siae) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid( job_seeker=job_seeker, for_siae=siae ) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker, for_siae=siae) self.assertTrue(has_considered_valid) # A diagnosis made by a prescriber takes precedence. self.assertEqual(last_considered_valid, prescriber_diagnosis) self.assertIsNone(last_expired) # Has an expired Itou diagnoses made by another SIAE. job_seeker = JobSeekerFactory() siae1 = SiaeWithMembershipFactory() siae2 = SiaeWithMembershipFactory() expired_diagnosis = ExpiredEligibilityDiagnosisMadeBySiaeFactory(job_seeker=job_seeker, author_siae=siae1) # From `siae` perspective. last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker, for_siae=siae1) self.assertEqual(last_expired, expired_diagnosis) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker, for_siae=siae2) self.assertIsNone(last_expired) # Has 2 Itou diagnoses: 1 is considered expired and the second is considered valid. job_seeker = JobSeekerFactory() ExpiredEligibilityDiagnosisFactory(job_seeker=job_seeker) EligibilityDiagnosisFactory(job_seeker=job_seeker) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) last_considered_valid = EligibilityDiagnosis.objects.last_considered_valid(job_seeker=job_seeker) # When has a valid diagnosis, `last_expired` return None self.assertIsNotNone(last_considered_valid) self.assertIsNone(last_expired) # Has 2 Itou diagnoses expired: the last one expired must be returned. job_seeker = JobSeekerFactory() date_6m = ( timezone.now() - relativedelta(months=EligibilityDiagnosis.EXPIRATION_DELAY_MONTHS) - relativedelta(day=1) ) date_12m = date_6m - relativedelta(months=6) expired_diagnosis_old = EligibilityDiagnosisFactory(job_seeker=job_seeker, created_at=date_12m) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) self.assertEqual(last_expired, expired_diagnosis_old) expired_diagnosis_last = EligibilityDiagnosisFactory(job_seeker=job_seeker, created_at=date_6m) last_expired = EligibilityDiagnosis.objects.last_expired(job_seeker=job_seeker) self.assertEqual(last_expired, expired_diagnosis_last)
def test_find_or_create_approval__create(self): developer = UserFactory( email=settings.AI_EMPLOYEES_STOCK_DEVELOPER_EMAIL) command = self.command # No PASS IAE. job_seeker = JobSeekerFactory( nir=getattr(CleanedAiCsvFileMock(), NIR_COL)) created, approval, _ = command.find_or_create_approval( job_seeker=job_seeker, created_by=developer) self.assertTrue(created) self.assertTrue(approval.is_valid) # Check attributes self.assertEqual(approval.user.pk, job_seeker.pk) self.assertEqual(approval.start_at, datetime.date(2021, 12, 1)) self.assertEqual(approval.end_at, datetime.date(2023, 11, 30)) self.assertEqual(approval.created_by.pk, developer.pk) self.assertEqual(approval.created_at, settings.AI_EMPLOYEES_STOCK_IMPORT_DATE) self.assertTrue(approval.is_from_ai_stock) # Clean job_seeker.delete() # Expired PASS IAE. approval_start_at = datetime.date.today() - relativedelta( years=Approval.DEFAULT_APPROVAL_YEARS, days=2) expired_approval = ApprovalFactory(user__nir=getattr( CleanedAiCsvFileMock(), NIR_COL), start_at=approval_start_at) job_seeker = expired_approval.user created, approval, _ = command.find_or_create_approval( job_seeker=job_seeker, created_by=developer) self.assertTrue(created) self.assertEqual(approval.user.pk, job_seeker.pk) self.assertTrue(approval.is_valid) self.assertEqual(job_seeker.approvals.count(), 2) # Clean job_seeker.delete() # PASS created after November 30th with a job application: # the employer tried to get a PASS IAE quicker. siae = SiaeWithMembershipFactory() previous_approval = ApprovalFactory( user__nir=getattr(CleanedAiCsvFileMock(), NIR_COL)) job_seeker = previous_approval.user job_application = JobApplicationSentBySiaeFactory( job_seeker=job_seeker, to_siae=siae, state=JobApplicationWorkflow.STATE_ACCEPTED, approval=previous_approval, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_AUTOMATIC, ) created, _, redelivered_approval = command.find_or_create_approval( job_seeker=job_seeker, created_by=developer) # assert previous approval does not exist anymore. self.assertFalse( Approval.objects.filter(pk=previous_approval.pk).exists()) # assert previous job application does not exist anymore. self.assertFalse( JobApplication.objects.filter(pk=job_application.pk).exists()) # assert a new PASS IAE has been delivered. self.assertTrue(created) self.assertTrue(redelivered_approval) # Clean job_seeker.delete() # PASS created after November 30th with a job application but not sent by this employer. siae = SiaeWithMembershipFactory() previous_approval = ApprovalFactory( user__nir=getattr(CleanedAiCsvFileMock(), NIR_COL)) job_seeker = previous_approval.user job_application = JobApplicationSentBySiaeFactory( job_seeker=job_seeker, state=JobApplicationWorkflow.STATE_ACCEPTED, approval=previous_approval, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_AUTOMATIC, ) created, _, redelivered_approval = command.find_or_create_approval( job_seeker=job_seeker, created_by=developer) # assert previous approval does not exist anymore. self.assertFalse( Approval.objects.filter(pk=previous_approval.pk).exists()) # assert previous job application does not exist anymore. self.assertFalse( JobApplication.objects.filter(pk=job_application.pk).exists()) # assert a new PASS IAE has been delivered. self.assertTrue(created) self.assertTrue(redelivered_approval) # Clean job_seeker.delete() # Multiple accepted job applications linked to this approval. Raise an error if dry run is not set. siae = SiaeWithMembershipFactory() previous_approval = ApprovalFactory( user__nir=getattr(CleanedAiCsvFileMock(), NIR_COL)) job_seeker = previous_approval.user job_application = JobApplicationSentBySiaeFactory( job_seeker=job_seeker, to_siae=siae, state=JobApplicationWorkflow.STATE_ACCEPTED, approval=previous_approval, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_AUTOMATIC, ) JobApplicationSentBySiaeFactory( job_seeker=job_seeker, state=JobApplicationWorkflow.STATE_ACCEPTED, approval=previous_approval, approval_delivery_mode=JobApplication. APPROVAL_DELIVERY_MODE_AUTOMATIC, ) created, approval, redelivered_approval = command.find_or_create_approval( job_seeker=job_seeker, created_by=developer) self.assertFalse(created) self.assertFalse(redelivered_approval) self.assertTrue(previous_approval.pk, approval.pk) job_seeker.delete()
def test_number_with_spaces(self): approval = ApprovalFactory(number="999990000001") expected = "99999 00 00001" self.assertEqual(approval.number_with_spaces, expected)
def test_originates_from_itou(self): approval = ApprovalFactory(number="999990000001") self.assertTrue(approval.originates_from_itou) approval = PoleEmploiApprovalFactory(number="625741810182") self.assertFalse(approval.originates_from_itou)
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_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)