Пример #1
0
 def test_cancel(self):
     # Hiring date is today: cancellation should be possible.
     job_application = JobApplicationWithApprovalFactory(
         state=JobApplicationWorkflow.STATE_ACCEPTED)
     siae_user = job_application.to_siae.members.first()
     self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)
     url = reverse("apply:cancel",
                   kwargs={"job_application_id": job_application.pk})
     response = self.client.get(url)
     self.assertEqual(response.status_code, 302)
     job_application.refresh_from_db()
     self.assertTrue(job_application.state.is_cancelled)
Пример #2
0
    def test_can_be_cancelled(self):
        today = datetime.date.today()
        cancellation_days_in_future = relativedelta(
            days=JobApplication.CANCELLATION_DAYS_AFTER_HIRING_STARTED)
        cancellation_period_end = today - cancellation_days_in_future

        job_application_future_ok = JobApplicationWithApprovalFactory(
            hiring_start_at=cancellation_period_end)
        self.assertTrue(job_application_future_ok.can_be_cancelled)

        job_application_future_not_ok = JobApplicationWithApprovalFactory(
            hiring_start_at=(cancellation_period_end -
                             relativedelta(days=365)))
        self.assertFalse(job_application_future_not_ok.can_be_cancelled)
Пример #3
0
 def test_cannot_cancel(self):
     cancellation_period_end = datetime.date.today() - relativedelta(
         days=JobApplication.CANCELLATION_DAYS_AFTER_HIRING_STARTED)
     job_application = JobApplicationWithApprovalFactory(
         state=JobApplicationWorkflow.STATE_ACCEPTED,
         hiring_start_at=(cancellation_period_end - relativedelta(days=1)),
     )
     siae_user = job_application.to_siae.members.first()
     self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)
     url = reverse("apply:cancel",
                   kwargs={"job_application_id": job_application.pk})
     response = self.client.get(url)
     self.assertEqual(response.status_code, 302)
     job_application.refresh_from_db()
     self.assertFalse(job_application.state.is_cancelled)
Пример #4
0
 def setUp(self):
     self.job_application = JobApplicationWithApprovalFactory(state=JobApplicationWorkflow.STATE_ACCEPTED)
     self.siae = self.job_application.to_siae
     self.siae_user = self.job_application.to_siae.members.first()
     self.approval = self.job_application.approval
     self.job_seeker = self.job_application.job_seeker
     self.pe_approval = PoleEmploiApprovalFactory()
Пример #5
0
    def test_has_matching_pass_iae_that_belongs_to_another_siae(self):
        """
        Make sure to NOT to redirect to job applications belonging to other SIAEs,
        as this would produce a 404.
        """

        # Initial approvals (PE and PASS)
        self.set_up_pe_approval()

        # Create a job application with a PASS IAE created from a `PoleEmploiApproval`
        # that belongs to another siae.
        job_seeker = JobSeekerFactory()
        pe_approval = PoleEmploiApprovalFactory()
        job_application = JobApplicationWithApprovalFactory(
            state=JobApplicationWorkflow.STATE_ACCEPTED,
            approval__number=pe_approval.number,
            approval__user=job_seeker,
            job_seeker=job_seeker,
        )

        another_siae = job_application.to_siae
        self.assertNotEqual(another_siae, self.siae)

        # This is the current user (NOT a member of `another_siae`).
        self.client.login(username=self.siae_user.email, password=DEFAULT_PASSWORD)

        # The current user should not be able to use the PASS IAE used by another SIAE.
        response = self.client.get(self.url, {"number": job_application.approval.number})
        self.assertNotContains(response, "Continuer")
Пример #6
0
    def test_download_approval_missing_diagnosis_ai(self, *args, **kwargs):
        """
        Given an existing job application with an approval delivered by Itou
        when importing AI employees, when an AI tries to download it as PDF, it works.
        """

        # On November 30th, 2021, AI were delivered approvals without a diagnosis.
        # See itou.users.management.commands.import_ai_employees.
        approval_created_at = settings.AI_EMPLOYEES_STOCK_IMPORT_DATE
        approval_created_by = UserFactory(email=settings.AI_EMPLOYEES_STOCK_DEVELOPER_EMAIL)
        job_application = JobApplicationWithApprovalFactory(
            eligibility_diagnosis=None,
            approval__created_at=approval_created_at,
            approval__created_by=approval_created_by,
        )

        siae_member = job_application.to_siae.members.first()
        self.client.login(username=siae_member.email, password=DEFAULT_PASSWORD)

        response = self.client.get(
            reverse("approvals:approval_as_pdf", kwargs={"job_application_id": job_application.pk})
        )

        self.assertEqual(response.status_code, 200)
        self.assertIn("pdf", response.get("Content-Type"))
Пример #7
0
    def test_cannot_cancel(self, *args, **kwargs):
        job_application = JobApplicationWithApprovalFactory(
            state=JobApplicationWorkflow.STATE_ACCEPTED,
            hiring_start_at=timezone.localdate() + relativedelta(days=1),
        )
        siae_user = job_application.to_siae.members.first()
        # Add a blocking employee record
        EmployeeRecordFactory(job_application=job_application, status=EmployeeRecord.Status.PROCESSED)

        self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)
        url = reverse("apply:cancel", kwargs={"job_application_id": job_application.pk})
        response = self.client.get(url)
        next_url = reverse("apply:details_for_siae", kwargs={"job_application_id": job_application.pk})
        self.assertRedirects(response, next_url)

        job_application.refresh_from_db()
        self.assertFalse(job_application.state.is_cancelled)
Пример #8
0
 def test_mise_a_jour_pass_iae_invalid_token(self, mock_post):
     """If the API answers with a non-200 http code, mise_a_jour_pass_iae will return false"""
     job_application = JobApplicationWithApprovalFactory()
     with self.assertRaises(PoleEmploiMiseAJourPassIAEException):
         mise_a_jour_pass_iae(
             job_application, POLE_EMPLOI_PASS_APPROVED, "some_valid_encrypted_identifier", "some_valid_token"
         )
         mock_post.assert_called()
Пример #9
0
    def test_suspend_approval(self):
        """
        Test the creation of a suspension.
        """

        today = timezone.localdate()

        job_application = JobApplicationWithApprovalFactory(
            state=JobApplicationWorkflow.STATE_ACCEPTED,
            hiring_start_at=today - relativedelta(days=1),
        )

        # Ensure that the job_application cannot be canceled.
        EmployeeRecordFactory(job_application=job_application, status=EmployeeRecord.Status.PROCESSED)

        approval = job_application.approval
        self.assertEqual(0, approval.suspension_set.count())

        siae_user = job_application.to_siae.members.first()
        self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)

        back_url = "/"
        params = urlencode({"back_url": back_url})
        url = reverse("approvals:suspend", kwargs={"approval_id": approval.pk})
        url = f"{url}?{params}"

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context["preview"], False)

        start_at = today
        end_at = today + relativedelta(days=10)

        post_data = {
            "start_at": start_at.strftime(DuetDatePickerWidget.INPUT_DATE_FORMAT),
            "end_at": end_at.strftime(DuetDatePickerWidget.INPUT_DATE_FORMAT),
            "reason": Suspension.Reason.SUSPENDED_CONTRACT,
            "reason_explanation": "",
            # Preview.
            "preview": "1",
        }

        # Go to preview.
        response = self.client.post(url, data=post_data)
        self.assertEqual(response.status_code, 200)
        self.assertEqual(response.context["preview"], True)

        # Save to DB.
        del post_data["preview"]
        post_data["save"] = 1

        response = self.client.post(url, data=post_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, back_url)

        self.assertEqual(1, approval.suspension_set.count())
        suspension = approval.suspension_set.first()
        self.assertEqual(suspension.created_by, siae_user)
Пример #10
0
    def test_as_job_seeker_is_not_authorized(self):
        """
        The search for PE approval screen as job seeker is not authorized
        """
        job_application = JobApplicationWithApprovalFactory(state=JobApplicationWorkflow.STATE_ACCEPTED)
        self.client.login(username=job_application.job_seeker.email, password=DEFAULT_PASSWORD)

        response = self.client.get(self.url)
        self.assertEqual(response.status_code, 404)
Пример #11
0
    def test_cancel(self, *args, **kwargs):
        # Hiring date is today: cancellation should be possible.
        job_application = JobApplicationWithApprovalFactory(state=JobApplicationWorkflow.STATE_ACCEPTED)
        siae_user = job_application.to_siae.members.first()
        self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)
        url = reverse("apply:cancel", kwargs={"job_application_id": job_application.pk})
        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        post_data = {
            "confirm": "true",
        }
        response = self.client.post(url, data=post_data)
        next_url = reverse("apply:details_for_siae", kwargs={"job_application_id": job_application.pk})
        self.assertRedirects(response, next_url)

        job_application.refresh_from_db()
        self.assertTrue(job_application.state.is_cancelled)
Пример #12
0
 def test_mise_a_jour_pass_iae_success_with_approval_accepted(self, mock_post):
     """
     Nominal scenario: an approval is **accepted**
     HTTP 200 + codeSortie = S001 is the only way mise_a_jour_pass_iae will return True"""
     job_application = JobApplicationWithApprovalFactory()
     result = mise_a_jour_pass_iae(
         job_application, POLE_EMPLOI_PASS_APPROVED, "some_valid_encrypted_identifier", "some_valid_token"
     )
     mock_post.assert_called()
     self.assertTrue(result)
Пример #13
0
 def test_mise_a_jour_pass_iae_failure(self, mock_post):
     """
     If the API answers with a non-S001 codeSortie (this is something in the json output)
     mise_a_jour_pass_iae will return false
     """
     job_application = JobApplicationWithApprovalFactory()
     with self.assertRaises(PoleEmploiMiseAJourPassIAEException):
         mise_a_jour_pass_iae(
             job_application, POLE_EMPLOI_PASS_APPROVED, "some_valid_encrypted_identifier", "some_valid_token"
         )
         mock_post.assert_called()
Пример #14
0
    def test_no_download_if_missing_diagnosis(self, *args, **kwargs):
        """
        Given an existing job application with an approval delivered by Itou but no
        diagnosis, when trying to download it as PDF, then it raises an error.
        """
        job_application = JobApplicationWithApprovalFactory(eligibility_diagnosis=None)

        siae_member = job_application.to_siae.members.first()
        self.client.login(username=siae_member.email, password=DEFAULT_PASSWORD)

        with self.assertRaises(ObjectDoesNotExist):
            self.client.get(reverse("approvals:approval_as_pdf", kwargs={"job_application_id": job_application.pk}))
Пример #15
0
    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)
Пример #16
0
    def test_pdfshift_api_is_down(self, *args, **kwargs):
        job_application = JobApplicationWithApprovalFactory()
        siae_member = job_application.to_siae.members.first()
        job_seeker = job_application.job_seeker
        EligibilityDiagnosisFactory(job_seeker=job_seeker)

        self.client.login(username=siae_member.email,
                          password=DEFAULT_PASSWORD)

        with self.assertRaises(ConnectionAbortedError):
            self.client.get(
                reverse("approvals:approval_as_pdf",
                        kwargs={"job_application_id": job_application.pk}))
Пример #17
0
    def test_no_download_if_missing_diagnosis(self, *args, **kwargs):
        job_application = JobApplicationWithApprovalFactory()
        siae_member = job_application.to_siae.members.first()

        # An approval has been delivered by Itou but there is no diagnosis.
        # It should raise an error.
        # EligibilityDiagnosisFactory(job_seeker=job_seeker)

        self.client.login(username=siae_member.email,
                          password=DEFAULT_PASSWORD)

        with self.assertRaises(ObjectDoesNotExist):
            self.client.get(
                reverse("approvals:approval_as_pdf",
                        kwargs={"job_application_id": job_application.pk}))
Пример #18
0
    def test_approval_in_the_future(self):
        """
        The search for PE approval screen should display that there is no results
        if a PE approval number was searched for but it is in the future
        """
        today = timezone.now().date()

        pe_approval = PoleEmploiApprovalFactory(start_at=today + relativedelta(days=10))

        job_application = JobApplicationWithApprovalFactory(state=JobApplicationWorkflow.STATE_ACCEPTED)
        siae_user = job_application.to_siae.members.first()
        self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)

        response = self.client.get(self.url, {"number": pe_approval.number})
        self.assertNotContains(response, "Continuer")
Пример #19
0
    def test_download_job_app_approval_as_pdf(self, *args, **kwargs):
        job_application = JobApplicationWithApprovalFactory()
        siae_member = job_application.to_siae.members.first()
        job_seeker = job_application.job_seeker
        EligibilityDiagnosisFactory(job_seeker=job_seeker)

        self.client.login(username=siae_member.email,
                          password=DEFAULT_PASSWORD)

        response = self.client.get(
            reverse("approvals:approval_as_pdf",
                    kwargs={"job_application_id": job_application.pk}))

        self.assertEqual(response.status_code, 200)
        self.assertIn("pdf", response.get("Content-Type"))
Пример #20
0
    def test_download_job_app_approval_as_pdf(self, *args, **kwargs):
        """
        Given an existing job application with a PASS IAE and a diagnosis,
        when trying to download it as PDF, then it works.
        """
        job_application = JobApplicationWithApprovalFactory()

        siae_member = job_application.to_siae.members.first()
        self.client.login(username=siae_member.email, password=DEFAULT_PASSWORD)

        response = self.client.get(
            reverse("approvals:approval_as_pdf", kwargs={"job_application_id": job_application.pk})
        )

        self.assertEqual(response.status_code, 200)
        self.assertIn("pdf", response.get("Content-Type"))
Пример #21
0
    def test_update_suspension(self):
        """
        Test the update of a suspension.
        """

        today = timezone.localdate()

        job_application = JobApplicationWithApprovalFactory(
            state=JobApplicationWorkflow.STATE_ACCEPTED,
            # Ensure that the job_application cannot be canceled.
            hiring_start_at=today - relativedelta(days=1),
        )

        approval = job_application.approval
        siae_user = job_application.to_siae.members.first()
        start_at = today
        end_at = today + relativedelta(days=10)

        suspension = SuspensionFactory(approval=approval, start_at=start_at, end_at=end_at, created_by=siae_user)

        self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)

        back_url = "/"
        params = urlencode({"back_url": back_url})
        url = reverse("approvals:suspension_update", kwargs={"suspension_id": suspension.pk})
        url = f"{url}?{params}"

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        new_end_at = end_at + relativedelta(days=30)

        post_data = {
            "start_at": suspension.start_at.strftime(DuetDatePickerWidget.INPUT_DATE_FORMAT),
            "end_at": new_end_at.strftime(DuetDatePickerWidget.INPUT_DATE_FORMAT),
            "reason": suspension.reason,
            "reason_explanation": suspension.reason_explanation,
        }

        response = self.client.post(url, data=post_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, back_url)

        self.assertEqual(1, approval.suspension_set.count())
        suspension = approval.suspension_set.first()
        self.assertEqual(suspension.updated_by, siae_user)
        self.assertEqual(suspension.end_at, new_end_at)
Пример #22
0
    def test_cancellation_not_allowed(self):
        today = datetime.date.today()

        # Outside cancellation delay
        job_application = JobApplicationWithApprovalFactory(
            hiring_start_at=(today - relativedelta(days=365)))
        cancellation_user = job_application.to_siae.active_members.first()

        # xworkflows.base.AbortTransition
        with self.assertRaises(xwf_models.AbortTransition):
            job_application.cancel(user=cancellation_user)

        # Wrong state
        job_application = JobApplicationWithApprovalFactory(
            hiring_start_at=today, state=JobApplicationWorkflow.STATE_NEW)
        cancellation_user = job_application.to_siae.active_members.first()
        with self.assertRaises(xwf_models.AbortTransition):
            job_application.cancel(user=cancellation_user)
Пример #23
0
    def set_up_pe_approval(self, with_job_application=True):
        # pylint: disable=attribute-defined-outside-init
        self.pe_approval = PoleEmploiApprovalFactory()

        self.siae = SiaeWithMembershipFactory()
        self.siae_user = self.siae.members.first()
        if with_job_application:
            self.job_application = JobApplicationWithApprovalFactory(
                to_siae=self.siae,
                state=JobApplicationWorkflow.STATE_ACCEPTED,
                approval__number=self.pe_approval.number,
            )
            self.approval = self.job_application.approval
            self.job_seeker = self.job_application.job_seeker
        else:
            self.approval = None
            self.job_seeker = None
Пример #24
0
    def test_download_approval_even_if_diagnosis_is_missing(
            self, *args, **kwargs):
        job_application = JobApplicationWithApprovalFactory()
        siae_member = job_application.to_siae.members.first()

        # An approval has been delivered but it does not come from Itou.
        # Therefore, the linked diagnosis exists but is not in our database.
        # Don't create a diagnosis.
        # EligibilityDiagnosisFactory(job_seeker=job_seeker)

        self.client.login(username=siae_member.email,
                          password=DEFAULT_PASSWORD)

        response = self.client.get(
            reverse("approvals:approval_as_pdf",
                    kwargs={"job_application_id": job_application.pk}))

        self.assertEqual(response.status_code, 200)
        self.assertIn("pdf", response.get("Content-Type"))
Пример #25
0
    def test_cancel_delete_linked_approval(self):
        job_application = JobApplicationWithApprovalFactory()
        self.assertEqual(job_application.job_seeker.approvals.count(), 1)
        self.assertEqual(
            JobApplication.objects.filter(
                approval=job_application.approval).count(), 1)

        cancellation_user = job_application.to_siae.active_members.first()
        job_application.cancel(user=cancellation_user)

        self.assertEqual(job_application.state,
                         JobApplicationWorkflow.STATE_CANCELLED)

        job_application.refresh_from_db()
        self.assertFalse(job_application.approval)
Пример #26
0
    def test_download_approval_even_if_diagnosis_is_missing(self, *args, **kwargs):
        """
        Given an existing job application with an approval delivered by Pôle emploi
        but no diagnosis, when trying to download it as PDF, then it works.
        """

        # An approval has been delivered but it does not come from Itou.
        # Therefore, the linked diagnosis exists but is not in our database.
        job_application = JobApplicationWithApprovalFactory(
            eligibility_diagnosis=None, approval__number="625741810181"
        )

        siae_member = job_application.to_siae.members.first()
        self.client.login(username=siae_member.email, password=DEFAULT_PASSWORD)

        response = self.client.get(
            reverse("approvals:approval_as_pdf", kwargs={"job_application_id": job_application.pk})
        )

        self.assertEqual(response.status_code, 200)
        self.assertIn("pdf", response.get("Content-Type"))
Пример #27
0
    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é.")
Пример #28
0
    def test_cancel_do_not_delete_linked_approval(self):

        # The approval is linked to two accepted job applications
        job_application = JobApplicationWithApprovalFactory()
        approval = job_application.approval
        JobApplicationWithApprovalFactory(
            approval=approval, job_seeker=job_application.job_seeker)

        self.assertEqual(job_application.job_seeker.approvals.count(), 1)
        self.assertEqual(
            JobApplication.objects.filter(approval=approval).count(), 2)

        cancellation_user = job_application.to_siae.active_members.first()
        job_application.cancel(user=cancellation_user)

        self.assertEqual(job_application.state,
                         JobApplicationWorkflow.STATE_CANCELLED)

        job_application.refresh_from_db()
        self.assertTrue(job_application.approval)
Пример #29
0
    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)
Пример #30
0
    def test_delete_suspension(self):
        """
        Test the deletion of a suspension.
        """

        today = timezone.localdate()

        job_application = JobApplicationWithApprovalFactory(
            state=JobApplicationWorkflow.STATE_ACCEPTED,
            # Ensure that the job_application cannot be canceled.
            hiring_start_at=today - relativedelta(days=1),
        )

        approval = job_application.approval
        siae_user = job_application.to_siae.members.first()
        start_at = today
        end_at = today + relativedelta(days=10)

        suspension = SuspensionFactory(approval=approval, start_at=start_at, end_at=end_at, created_by=siae_user)

        self.client.login(username=siae_user.email, password=DEFAULT_PASSWORD)

        back_url = "/"
        params = urlencode({"back_url": back_url})
        url = reverse("approvals:suspension_delete", kwargs={"suspension_id": suspension.pk})
        url = f"{url}?{params}"

        response = self.client.get(url)
        self.assertEqual(response.status_code, 200)

        post_data = {"confirm": "true"}

        response = self.client.post(url, data=post_data)
        self.assertEqual(response.status_code, 302)
        self.assertRedirects(response, back_url)

        self.assertEqual(0, approval.suspension_set.count())