Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Le badge 20+ candidatures sur les résultats de recherche ne doit pas inclure de candidatures archivées #5378

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 8 additions & 5 deletions itou/companies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -557,14 +557,17 @@ def with_job_applications_count(self, filters=None):
),
)

def with_annotation_is_popular(self):
def with_annotation_is_overwhelmed(self):
# Avoid a circular import
from itou.job_applications.models import JobApplicationWorkflow

job_apps_filters = {"jobapplication__state__in": JobApplicationWorkflow.PENDING_STATES}
job_apps_filters = {
"jobapplication__state__in": JobApplicationWorkflow.PENDING_STATES,
"jobapplication__archived_at": None,
}
annotation = self.with_job_applications_count(filters=job_apps_filters).annotate(
is_popular=Case(
When(job_applications_count__gte=self.model.POPULAR_THRESHOLD, then=True),
is_overwhelmed=Case(
When(job_applications_count__gte=self.model.OVERWHELMED_THRESHOLD, then=True),
default=False,
output_field=BooleanField(),
)
Expand Down Expand Up @@ -601,7 +604,7 @@ class JobDescription(models.Model):
"""

MAX_UI_RANK = 32767
POPULAR_THRESHOLD = 20
OVERWHELMED_THRESHOLD = 20
# Max number or workable hours per week in France (Code du Travail)
MAX_WORKED_HOURS_PER_WEEK = 48

Expand Down
2 changes: 1 addition & 1 deletion itou/templates/apply/submit/application/jobs.html
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<label class="fw-bold stretched-link order-2 order-md-1 m-0" for="{{ choice.id_for_label }}">
{{ choice.choice_label }}
</label>
{% if job_description.is_popular %}
{% if job_description.is_overwhelmed %}
<div class="order-1 order-md-2">
<span class="badge badge-sm rounded-pill bg-accent-03 text-primary ms-0 ms-lg-2 mt-1 mt-lg-0"><i class="ri-group-line"></i>20+ candidatures</span>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu pourrais ici aussi utiliser job_description.OVERWHELMED_THRESHOLD au lieu de 20 (comme dans _card_jobdescription.html)

</div>
Expand Down
4 changes: 2 additions & 2 deletions itou/templates/companies/includes/_card_jobdescription.html
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,10 @@
{% if job_description.is_external %} {% matomo_event "candidature" "clic" "clic-card-fichedeposte-externe" %} rel="noopener" target="_blank" aria-label="Visiter l'offre sur le site d'origine" {% else %} {% matomo_event "candidature" "clic" "clic-card-fichedeposte" %} aria-label="Aller vers la description de ce poste" {% endif %}>
{{ job_description.display_name | capfirst }}
</a>
{% if job_description.is_popular %}
{% if job_description.is_overwhelmed %}
<span class="badge badge-sm rounded-pill bg-accent-03 text-primary">
<i class="ri-group-line me-1" aria-hidden="true"></i>
{{ job_description.POPULAR_THRESHOLD }}+<span class="ms-1">candidatures</span>
{{ job_description.OVERWHELMED_THRESHOLD }}+<span class="ms-1">candidatures</span>
</span>
{% endif %}
<ul class="c-box--results__list-contact flex-md-grow-1 mt-1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@
{% endif %}
<a href="{{ job_url }}" class="fw-bold text-decoration-none stretched-link" {% matomo_event "candidature" "clic" "clic-metiers" %}>{{ job.display_name }}</a>
{% endif %}
{% if job.is_popular %}
{% if job.is_overwhelmed %}
<span class="badge badge-sm rounded-pill bg-accent-03 text-primary">
<i class="ri-group-line me-1" aria-hidden="true"></i>
{{ job.POPULAR_THRESHOLD }}+<span class="ms-1">candidatures</span>
{{ job.OVERWHELMED_THRESHOLD }}+<span class="ms-1">candidatures</span>
</span>
{% endif %}
<p class="fs-sm mb-0 mt-1">
Expand Down
4 changes: 2 additions & 2 deletions itou/templates/companies/includes/_siae_jobdescription.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
class="fw-bold stretched-link order-2 order-md-1"
{% matomo_event "candidature" "clic" "clic-metiers" %}>{{ job.display_name }}</a>
{% endif %}
{% if job.is_popular %}
{% if job.is_overwhelmed %}
<div class="order-1 order-md-2">
<span class="badge badge-sm rounded-pill bg-accent-03 text-primary ms-0 ms-lg-2 mt-1 mt-lg-0"><i class="ri-group-line"></i>{{ job.POPULAR_THRESHOLD }}+ candidatures</span>
<span class="badge badge-sm rounded-pill bg-accent-03 text-primary ms-0 ms-lg-2 mt-1 mt-lg-0"><i class="ri-group-line"></i>{{ job.OVERWHELMED_THRESHOLD }}+ candidatures</span>
</div>
{% endif %}
</div>
Expand Down
2 changes: 1 addition & 1 deletion itou/www/apply/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def __init__(self, company, *args, **kwargs):
super().__init__(*args, **kwargs)

self.fields["selected_jobs"].queryset = (
company.job_description_through.active().with_annotation_is_popular().prefetch_related("appellation")
company.job_description_through.active().with_annotation_is_overwhelmed().prefetch_related("appellation")
)
if not self.initial.get("selected_jobs"):
self.initial["spontaneous_application"] = True
Expand Down
8 changes: 4 additions & 4 deletions itou/www/search/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ def get_results_page_and_counts(self, siaes, job_descriptions):
siaes.prefetch_related(
Prefetch(
lookup="job_description_through",
queryset=JobDescription.objects.with_annotation_is_popular()
queryset=JobDescription.objects.with_annotation_is_overwhelmed()
.filter(company__in=siaes, is_active=True)
.select_related("appellation", "location", "company"),
to_attr="active_job_descriptions",
Expand Down Expand Up @@ -255,7 +255,7 @@ def get_results_page_and_counts(self, siaes, job_descriptions):
job_descriptions = job_descriptions.order_by(F("source_kind").asc(nulls_first=True), "-updated_at")

page = pager(job_descriptions, self.request.GET.get("page"), items_per_page=10)
# Prefer a prefetch_related over annotating the entire queryset with_annotation_is_popular().
# Prefer a prefetch_related over annotating the entire queryset with_annotation_is_overwhelmed().
# That annotation is quite expensive and PostgreSQL runs it on the entire queryset, even
# though we don’t sort or group by that column. It would be smarter to apply the limit
# before computing the annotation, but that’s not what PostgreSQL 15 does on 2024-02-21.
Expand All @@ -267,8 +267,8 @@ def get_results_page_and_counts(self, siaes, job_descriptions):
)
)
for job_description in page.object_list:
job_description.is_popular = (
len(job_description.jobapplication_set_pending) >= job_description._meta.model.POPULAR_THRESHOLD
job_description.is_overwhelmed = (
len(job_description.jobapplication_set_pending) >= job_description._meta.model.OVERWHELMED_THRESHOLD
)
return PageAndCounts(
results_page=page,
Expand Down
46 changes: 28 additions & 18 deletions tests/companies/test_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -347,42 +347,52 @@ def test_can_have_prior_action(self):


class TestJobDescriptionQuerySet:
def test_with_annotation_is_popular(self):
def test_with_annotation_is_overwhelmed(self):
company = CompanyFactory(with_jobs=True)
job_seeker = JobSeekerFactory() # We don't care if it's always the same
siae_job_descriptions = company.job_description_through.all()

# Test attribute presence
siae_job_description = JobDescription.objects.with_annotation_is_popular().first()
assert hasattr(siae_job_description, "is_popular")

# Test popular threshold: popular job description
popular_job_description = siae_job_descriptions[0]
for _ in range(JobDescription.POPULAR_THRESHOLD + 1):
JobApplicationFactory(to_company=company, selected_jobs=[popular_job_description], job_seeker=job_seeker)

assert JobDescription.objects.with_annotation_is_popular().get(pk=popular_job_description.pk).is_popular
siae_job_description = JobDescription.objects.with_annotation_is_overwhelmed().first()
assert hasattr(siae_job_description, "is_overwhelmed")

# Test overwhelmed threshold: overwhelmed job description
overwhelmed_job_description = siae_job_descriptions[0]
for _ in range(JobDescription.OVERWHELMED_THRESHOLD + 1):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tu pourrais en profiter pour le remplacer par JobApplicationFactory.create_batch(JobDescription.OVERWHELMED_THRESHOLD + 1, to_company=company, selected_jobs=[overwhelmed_job_description], job_seeker=job_seeker)

JobApplicationFactory(
to_company=company, selected_jobs=[overwhelmed_job_description], job_seeker=job_seeker
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Il faudrait aussi vérifier que les candidatures archivées ne comptent pas, peut être en archivant une des candidatures créées ici ?

)

assert (
JobDescription.objects.with_annotation_is_overwhelmed()
.get(pk=overwhelmed_job_description.pk)
.is_overwhelmed
)

# Test popular threshold: unpopular job description
unpopular_job_description = siae_job_descriptions[1]
JobApplicationFactory(to_company=company, selected_jobs=[unpopular_job_description])
# Test overwhelmed threshold: non overwhelmed job description
non_overwhelmed_job_description = siae_job_descriptions[1]
JobApplicationFactory(to_company=company, selected_jobs=[non_overwhelmed_job_description])

assert not JobDescription.objects.with_annotation_is_popular().get(pk=unpopular_job_description.pk).is_popular
assert (
not JobDescription.objects.with_annotation_is_overwhelmed()
.get(pk=non_overwhelmed_job_description.pk)
.is_overwhelmed
)

# Popular job descriptions count related **pending** job applications.
# Overwhelmed job descriptions count related **pending** job applications.
# They should ignore other states.
job_description = siae_job_descriptions[2]
threshold_exceeded = JobDescription.POPULAR_THRESHOLD + 1
threshold_exceeded = JobDescription.OVERWHELMED_THRESHOLD + 1

JobApplicationFactory.create_batch(
threshold_exceeded,
to_company=company,
job_seeker=job_seeker,
selected_jobs=[popular_job_description],
selected_jobs=[overwhelmed_job_description],
state=JobApplicationState.ACCEPTED,
)

assert not JobDescription.objects.with_annotation_is_popular().get(pk=job_description.pk).is_popular
assert not JobDescription.objects.with_annotation_is_overwhelmed().get(pk=job_description.pk).is_overwhelmed

def test_with_job_applications_count(self):
company = CompanyFactory(with_jobs=True)
Expand Down
32 changes: 20 additions & 12 deletions tests/www/search/__snapshots__/tests.ambr
Original file line number Diff line number Diff line change
Expand Up @@ -917,12 +917,14 @@
"companies_jobdescription"."field_history",
"companies_jobdescription"."creation_source",
COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE "job_applications_jobapplication"."state" IN (%s, %s, %s)) AS "job_applications_count",
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) AS "job_applications_count",
CASE
WHEN COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE ("job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
ELSE %s
END AS "is_popular",
END AS "is_overwhelmed",
"jobs_appellation"."updated_at",
"jobs_appellation"."code",
"jobs_appellation"."name",
Expand Down Expand Up @@ -1302,12 +1304,14 @@
"companies_jobdescription"."field_history",
"companies_jobdescription"."creation_source",
COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE "job_applications_jobapplication"."state" IN (%s, %s, %s)) AS "job_applications_count",
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) AS "job_applications_count",
CASE
WHEN COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE ("job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
ELSE %s
END AS "is_popular",
END AS "is_overwhelmed",
"jobs_appellation"."updated_at",
"jobs_appellation"."code",
"jobs_appellation"."name",
Expand Down Expand Up @@ -1688,12 +1692,14 @@
"companies_jobdescription"."field_history",
"companies_jobdescription"."creation_source",
COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE "job_applications_jobapplication"."state" IN (%s, %s, %s)) AS "job_applications_count",
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) AS "job_applications_count",
CASE
WHEN COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE ("job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
ELSE %s
END AS "is_popular",
END AS "is_overwhelmed",
"jobs_appellation"."updated_at",
"jobs_appellation"."code",
"jobs_appellation"."name",
Expand Down Expand Up @@ -2073,12 +2079,14 @@
"companies_jobdescription"."field_history",
"companies_jobdescription"."creation_source",
COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE "job_applications_jobapplication"."state" IN (%s, %s, %s)) AS "job_applications_count",
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) AS "job_applications_count",
CASE
WHEN COUNT("job_applications_jobapplication_selected_jobs"."jobapplication_id") FILTER (
WHERE ("job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
WHERE ("job_applications_jobapplication"."archived_at" IS NULL
AND "job_applications_jobapplication"."state" IN (%s, %s, %s))) >= %s THEN %s
ELSE %s
END AS "is_popular",
END AS "is_overwhelmed",
"jobs_appellation"."updated_at",
"jobs_appellation"."code",
"jobs_appellation"."name",
Expand Down
Loading
Loading