diff --git a/tests/www/apply/__snapshots__/test_process_outward_transfer.ambr b/tests/www/apply/__snapshots__/test_process_outward_transfer.ambr
new file mode 100644
index 00000000000..1cb0eda95e0
--- /dev/null
+++ b/tests/www/apply/__snapshots__/test_process_outward_transfer.ambr
@@ -0,0 +1,79 @@
+# serializer version: 1
+# name: test_step_1[progress]
+ '''
+
+
+
+
Transférer la candidature de Jane DOE
+
+
+
Rechercher un emploi inclusif
+
+
+
+
+
+ '''
+# ---
+# name: test_step_2[progress]
+ '''
+
+
+
+
Transférer la candidature de Jane DOE
+
+
+
Sélectionner les métiers recherchés
+
+
+
+
+
+ '''
+# ---
+# name: test_step_3[progress]
+ '''
+
+
+
+
Transférer la candidature de Jane DOE
+
+
+
Finaliser la candidature
+
+
+
+
+
+ '''
+# ---
diff --git a/tests/www/apply/test_process_outward_transfer.py b/tests/www/apply/test_process_outward_transfer.py
new file mode 100644
index 00000000000..abd8ae00de6
--- /dev/null
+++ b/tests/www/apply/test_process_outward_transfer.py
@@ -0,0 +1,487 @@
+import uuid
+from urllib.parse import quote
+
+import pytest
+from django.conf import settings
+from django.core.files.storage import storages
+from django.urls import reverse
+from freezegun import freeze_time
+from pytest_django.asserts import assertContains, assertNotContains, assertRedirects
+
+from itou.job_applications.enums import JobApplicationState
+from itou.job_applications.models import JobApplication
+from tests.cities.factories import create_city_guerande, create_city_vannes
+from tests.companies.factories import CompanyFactory, CompanyMembershipFactory, JobDescriptionFactory
+from tests.job_applications.factories import JobApplicationFactory
+from tests.jobs.factories import create_test_romes_and_appellations
+from tests.utils.test import parse_response_to_soup
+
+
+INWARD_TRANSFER_CONFIRM_BUTTON = """
+"""
+
+PREVIOUS_RESUME_TEXT = "Curriculum Vitae (CV) exitant"
+
+
+def test_anonymous_access(client):
+ job_application = JobApplicationFactory()
+ for viewname in (
+ "apply:job_application_outward_transfer_step_1",
+ "apply:job_application_outward_transfer_step_end",
+ ):
+ url = reverse(viewname, kwargs={"job_application_id": job_application.pk})
+ response = client.get(url)
+ assertRedirects(response, reverse("account_login") + f"?next={url}")
+
+ company = CompanyFactory(with_jobs=True, with_membership=True)
+ for viewname in (
+ "apply:job_application_outward_transfer_step_2",
+ "apply:job_application_outward_transfer_step_3",
+ "apply:job_application_inward_transfer",
+ ):
+ url = reverse(viewname, kwargs={"job_application_id": job_application.pk, "company_pk": company.pk})
+ response = client.get(url)
+ assertRedirects(response, reverse("account_login") + f"?next={url}")
+
+
+@pytest.mark.parametrize("state", JobApplicationState)
+def test_step_1_status_checks(client, state):
+ job_application = JobApplicationFactory(state=state)
+ employer = job_application.to_company.members.get()
+ client.force_login(employer)
+ response = client.get(
+ reverse("apply:job_application_outward_transfer_step_1", kwargs={"job_application_id": job_application.pk})
+ )
+ assert response.status_code == (200 if state == JobApplicationState.REFUSED else 404)
+
+
+def test_step_1(client, snapshot):
+ create_test_romes_and_appellations(["N1101"], appellations_per_rome=1)
+ vannes = create_city_vannes()
+ COMPANY_VANNES = "Entreprise Vannes"
+ other_company = CompanyFactory(name=COMPANY_VANNES, coords=vannes.coords, post_code="56760", with_membership=True)
+ job = JobDescriptionFactory(company=other_company)
+
+ guerande = create_city_guerande()
+ COMPANY_GUERANDE = "Entreprise Guérande"
+ CompanyFactory(name=COMPANY_GUERANDE, coords=guerande.coords, post_code="44350")
+
+ job_application = JobApplicationFactory(
+ state=JobApplicationState.REFUSED,
+ for_snapshot=True,
+ to_company__post_code="56760",
+ to_company__coords=vannes.coords,
+ to_company__city=vannes.name,
+ )
+ employer = job_application.to_company.members.get()
+ client.force_login(employer)
+
+ # Go th step 1
+ transfer_step_1_url = reverse(
+ "apply:job_application_outward_transfer_step_1", kwargs={"job_application_id": job_application.pk}
+ )
+ response = client.get(transfer_step_1_url)
+ assert str(parse_response_to_soup(response, ".c-stepper")) == snapshot(name="progress")
+
+ # search is centered on job app company city : only vannes companies should be displayed
+ assertContains(
+ response,
+ '2 résultats
',
+ html=True,
+ count=1,
+ )
+ assertContains(response, other_company.name.capitalize())
+ assertContains(response, job_application.to_company.name.capitalize())
+ assertNotContains(response, "Postuler")
+ assertContains(
+ response,
+ "Transférer la candidature",
+ count=2,
+ )
+
+ # Check outgoing links
+ transfer_step_2_base_url = reverse(
+ "apply:job_application_outward_transfer_step_2",
+ kwargs={"job_application_id": job_application.pk, "company_pk": other_company.pk},
+ )
+ assertContains(
+ response,
+ f"{transfer_step_2_base_url}?back_url={quote(transfer_step_1_url)}",
+ count=1,
+ )
+
+ company_card_url = (
+ reverse("companies_views:card", kwargs={"siae_id": other_company.pk})
+ + f"?back_url={quote(transfer_step_1_url)}"
+ )
+ assertContains(response, company_card_url, count=1)
+
+ job_card_url = (
+ reverse("companies_views:job_description_card", kwargs={"job_description_id": job.pk})
+ + f"?back_url={quote(transfer_step_1_url)}"
+ )
+ assertContains(response, job_card_url, count=1)
+
+ # Check company card
+ response = client.get(company_card_url)
+ assert str(parse_response_to_soup(response, ".c-stepper")) == snapshot(name="progress")
+ assertContains(
+ response,
+ f"{transfer_step_2_base_url}?back_url={quote(company_card_url)}",
+ count=2,
+ )
+ assertContains(response, job_card_url, count=1)
+ assertNotContains(response, "Postuler")
+ assertContains(
+ response,
+ "Transférer la candidature",
+ count=2,
+ )
+
+ # Check job description card
+ response = client.get(job_card_url)
+ assert str(parse_response_to_soup(response, ".c-stepper")) == snapshot(name="progress")
+ assertContains(
+ response,
+ f"{transfer_step_2_base_url}?job_description_id={job.pk}&back_url={quote(job_card_url)}",
+ count=1,
+ )
+ assertContains(response, company_card_url, count=1)
+ assertNotContains(response, "Postuler")
+ assertContains(
+ response,
+ "Transférer la candidature",
+ count=1,
+ )
+
+
+def test_step_2_same_company(client):
+ job_application = JobApplicationFactory(state=JobApplicationState.REFUSED, for_snapshot=True)
+ company = job_application.to_company
+ client.force_login(company.members.get())
+
+ transfer_step_1_url = reverse(
+ "apply:job_application_outward_transfer_step_1", kwargs={"job_application_id": job_application.pk}
+ )
+ transfer_step_2_base_url = reverse(
+ "apply:job_application_outward_transfer_step_2",
+ kwargs={"job_application_id": job_application.pk, "company_pk": job_application.to_company.pk},
+ )
+ transfer_step_2_url = f"{transfer_step_2_base_url}?back_url={quote(transfer_step_1_url)}"
+ response = client.get(transfer_step_2_url, follow=True)
+
+ inward_transfer_url = reverse(
+ "apply:job_application_inward_transfer",
+ kwargs={"job_application_id": job_application.pk, "company_pk": job_application.to_company.pk},
+ )
+ assertRedirects(response, f"{inward_transfer_url}?back_url={quote(transfer_step_1_url, safe='')}")
+ assertNotContains(response, INWARD_TRANSFER_CONFIRM_BUTTON, html=True)
+ assertContains(response, "Transfer impossible
")
+
+ # Check transfer view raises a 404
+ inward_transfer_post_url = reverse("apply:transfer", kwargs={"job_application_id": job_application.pk})
+ response = client.post(
+ inward_transfer_post_url,
+ data={"target_company_id": job_application.to_company.pk},
+ follow=True,
+ )
+ assertContains(response, "Une erreur est survenue lors du transfert de la candidature")
+
+ job_application.refresh_from_db()
+ assert job_application.state == JobApplicationState.REFUSED
+
+
+def test_step_2_inward_transfer(client):
+ job_application = JobApplicationFactory(state=JobApplicationState.REFUSED, for_snapshot=True)
+ employer = job_application.to_company.members.get()
+ other_company = CompanyMembershipFactory(user=employer).company
+ client.force_login(employer)
+
+ transfer_step_1_url = reverse(
+ "apply:job_application_outward_transfer_step_1", kwargs={"job_application_id": job_application.pk}
+ )
+ transfer_step_2_base_url = reverse(
+ "apply:job_application_outward_transfer_step_2",
+ kwargs={"job_application_id": job_application.pk, "company_pk": other_company.pk},
+ )
+ transfer_step_2_url = f"{transfer_step_2_base_url}?back_url={quote(transfer_step_1_url)}"
+ response = client.get(transfer_step_2_url, follow=True)
+
+ inward_transfer_url = reverse(
+ "apply:job_application_inward_transfer",
+ kwargs={"job_application_id": job_application.pk, "company_pk": other_company.pk},
+ )
+ assertRedirects(response, f"{inward_transfer_url}?back_url={quote(transfer_step_1_url, safe='')}")
+ assertContains(response, INWARD_TRANSFER_CONFIRM_BUTTON, html=True)
+ assertContains(response, "Confirmation du transfer
")
+ inward_transfer_post_url = reverse("apply:transfer", kwargs={"job_application_id": job_application.pk})
+ assertContains(response, f'