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

GEIQ: Afficher le diagnostic GEIQ d'une candidature acceptée dans le passé [GEN-1701] #4456

Merged
merged 5 commits into from
Jul 31, 2024
Merged
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
6 changes: 1 addition & 5 deletions itou/eligibility/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ def get_queryset(self, request):
class GEIQEligibilityDiagnosisAdmin(AbstractEligibilityDiagnosisAdmin):
raw_id_fields = AbstractEligibilityDiagnosisAdmin.raw_id_fields + ("author_geiq",)
readonly_fields = AbstractEligibilityDiagnosisAdmin.readonly_fields + (
"has_eligibility",
"is_valid",
"allowance_amount",
)
inlines = (
Expand All @@ -190,10 +190,6 @@ class GEIQEligibilityDiagnosisAdmin(AbstractEligibilityDiagnosisAdmin):
PkSupportRemarkInline,
)

@admin.display(boolean=True, description="éligibilité GEIQ confirmée")
def has_eligibility(self, obj):
return obj.eligibility_confirmed

@admin.display(description="montant de l'aide")
def allowance_amount(self, obj):
return f"{obj.allowance_amount} EUR"
Expand Down
7 changes: 1 addition & 6 deletions itou/eligibility/models/geiq.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,9 @@

class GEIQEligibilityDiagnosisQuerySet(CommonEligibilityDiagnosisQuerySet):
def authored_by_prescriber_or_geiq(self, geiq):
# In ordering, priority is given to prescriber authored diagnoses
return self.filter(
models.Q(author_geiq=geiq) | models.Q(author_prescriber_organization__isnull=False)
).order_by(models.F("author_prescriber_organization").desc(nulls_last=True), "-created_at")
).order_by("-created_at")

def diagnoses_for(self, job_seeker, for_geiq=None):
# Get *all* GEIQ diagnoses for given job seeker (even expired)
Expand Down Expand Up @@ -151,10 +150,6 @@ def save(self, *args, **kwargs):

return result

@property
def eligibility_confirmed(self) -> bool:
return bool(self.allowance_amount) and self.is_valid

@property
def allowance_amount(self) -> int:
return geiq_allowance_amount(self.author.is_prescriber_with_authorized_org, self.administrative_criteria.all())
Expand Down
2 changes: 1 addition & 1 deletion itou/templates/apply/includes/eligibility_badge.html
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
</span>
{% endif %}
{% elif is_subject_to_geiq_eligibility_rules %}
{% if geiq_eligibility_diagnosis.eligibility_confirmed %}
{% if geiq_eligibility_diagnosis.is_valid and geiq_eligibility_diagnosis.allowance_amount %}
<span class="badge badge-base rounded-pill bg-success-lighter text-success">
<i class="ri-check-line" aria-hidden="true"></i>
Éligibilité GEIQ confirmée
Expand Down
56 changes: 28 additions & 28 deletions itou/templates/apply/includes/geiq/geiq_diagnosis_details.html
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
{% if diagnosis.is_valid %}
{% if diagnosis.eligibility_confirmed %}
{% if diagnosis.is_valid or job_application.state.is_accepted and diagnosis %}
tonial marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
{% if diagnosis.is_valid or job_application.state.is_accepted and diagnosis %}
{% if diagnosis.is_valid or job_application.state.is_accepted %}

Copy link
Contributor Author

@tonial tonial Jul 30, 2024

Choose a reason for hiding this comment

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

N'est-il pas possible d'avoir une candidature acceptée vers un GEIQ sans diagnostic associé ?

Copy link
Contributor

Choose a reason for hiding this comment

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

Si. Mais même sans diagnostic, je pense qu'on souhaite mettre Éligibilité public prioritaire GEIQ non confirmée pour une candidature acceptée sans diag ? (mais il faudrait également adapter d'autres else/elif du template.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

C'est déjà traité alors : on passe dans le else en bas et à présent on marque Éligibilité public prioritaire GEIQ non confirmée même si ce n'est pas une entreprise 😎

{% if diagnosis.allowance_amount %}
<hr class="my-4">
<h3>Éligibilité public prioritaire GEIQ validée</h3>
{% else %}
<hr class="my-4">
<h3>Éligibilité public prioritaire GEIQ non confirmée</h3>
{% endif %}

{% if diagnosis.eligibility_confirmed %}
{% if diagnosis.allowance_amount %}
<p>
Éligibilité GEIQ confirmée par <b>{{ diagnosis.author.get_full_name }} ({{ diagnosis.author_structure.display_name }})</b>
</p>
Expand All @@ -26,7 +26,7 @@ <h4>Situation administrative du candidat</h4>
{% endif %}
{% endwith %}

{% if diagnosis.eligibility_confirmed %}
{% if diagnosis.allowance_amount %}
<p>
<b>Durée de validité du diagnostic :</b> du {{ diagnosis.created_at|date:"d/m/Y" }} au {{ diagnosis.expires_at|date:"d/m/Y" }}.
</p>
Expand All @@ -52,7 +52,7 @@ <h4>Situation administrative du candidat</h4>
</div>
</div>
{% endif %}
{% else %}
{% elif request.user.is_employer %}
{# Existing GEIQ, diagnosis but no allowance #}
<div class="alert alert-warning mt-4">
<div class="row">
Expand All @@ -77,37 +77,37 @@ <h4>Situation administrative du candidat</h4>
{% endif %}
{% else %}
{# Diagnosis either does not exist or has expired : this part is for GEIQ only #}
{% if request.user.is_employer %}
<hr class="my-4">
<div class="row align-items-center">
<div class="col-12 col-md">
<h3 class="mb-2 mb-md-0">Éligibilité public prioritaire GEIQ non confirmée</h3>
</div>
<hr class="my-4">
<div class="row align-items-center">
<div class="col-12 col-md">
<h3 class="mb-2 mb-md-0">Éligibilité public prioritaire GEIQ non confirmée</h3>
</div>
{% if request.user.is_employer %}
<div class="col-12 col-md-auto">
{% with back_and_next_url=request.get_full_path|urlencode %}
<a href="{% url 'apply:geiq_eligibility' job_application_id=job_application.pk %}?back_url={{ back_and_next_url }}&next_url={{ back_and_next_url }}" class="btn btn-secondary">
Vérifier
</a>
{% endwith %}
</div>
</div>
{# GEIQ eligibility diagnosis expired #}
{% if diagnosis and not diagnosis.is_valid %}
<div class="alert alert-warning mt-4">
<div class="row">
<div class="col-auto pe-0">
<i class="ri-alert-line ri-xl text-warning"></i>
</div>
<div class="col">
<p>
<b>Aide à l'accompagement GEIQ</b>
</p>
<p>
Le diagnostic du candidat a expiré le {{ diagnosis.expires_at|date:"d F Y" }}. Si vous souhaitez bénéficier d’une aide à l’accompagnement, veuillez renseigner à nouveau la situation administrative du candidat.
</p>
{# GEIQ eligibility diagnosis expired #}
{% if diagnosis and not diagnosis.is_valid %}
<div class="alert alert-warning mt-4">
<div class="row">
<div class="col-auto pe-0">
<i class="ri-alert-line ri-xl text-warning"></i>
</div>
<div class="col">
<p>
<b>Aide à l'accompagement GEIQ</b>
</p>
<p>
Le diagnostic du candidat a expiré le {{ diagnosis.expires_at|date:"d F Y" }}. Si vous souhaitez bénéficier d’une aide à l’accompagnement, veuillez renseigner à nouveau la situation administrative du candidat.
</p>
</div>
</div>
</div>
</div>
{% endif %}
{% endif %}
{% endif %}
</div>
{% endif %}
2 changes: 1 addition & 1 deletion itou/templates/apply/process_details.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ <h2>Informations générales</h2>
<div class="c-box mb-4">
<h3>Informations personnelles</h3>
{% include "apply/includes/job_seeker_info.html" with job_seeker=job_application.job_seeker job_application=job_application can_view_personal_information=can_view_personal_information can_edit_personal_information=can_edit_personal_information request=request csrf_token=csrf_token SenderKind=SenderKind only %}
{% if job_application.to_company.kind == CompanyKind.GEIQ and geiq_eligibility_diagnosis %}
{% if job_application.to_company.kind == CompanyKind.GEIQ %}
{# GEIQ eligibility details #}
{% include "apply/includes/geiq/geiq_diagnosis_details.html" with diagnosis=geiq_eligibility_diagnosis %}
{% else %}
Expand Down
42 changes: 22 additions & 20 deletions itou/www/apply/views/process_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,17 @@ def check_waiting_period(job_application):
raise PermissionDenied(apply_view_constants.ERROR_CANNOT_OBTAIN_NEW_FOR_PROXY)


def _get_geiq_eligibility_diagnosis_for_company(job_application):
# Get current GEIQ diagnosis or *last expired one*
return (
job_application.geiq_eligibility_diagnosis
or GEIQEligibilityDiagnosis.objects.diagnoses_for(
job_application.job_seeker, job_application.to_company
).first()
)
def _get_geiq_eligibility_diagnosis(job_application, only_prescriber):
tonial marked this conversation as resolved.
Show resolved Hide resolved
# Return the job_application diagnosis if it's accepted
if job_application.state.is_accepted:
# but not if the viewer is a prescriber and the diangosis was made by the company
if only_prescriber and job_application.geiq_eligibility_diagnosis.author_geiq:
return None
return job_application.geiq_eligibility_diagnosis
return GEIQEligibilityDiagnosis.objects.diagnoses_for(
job_application.job_seeker,
job_application.to_company if not only_prescriber else None,
).first()


@login_required
Expand Down Expand Up @@ -86,10 +89,11 @@ def details_for_jobseeker(request, job_application_id, template_name="apply/proc
)

back_url = get_safe_url(request, "back_url", fallback_url=reverse_lazy("apply:list_for_job_seeker"))
geiq_eligibility_diagnosis = None

if job_application.to_company.kind == CompanyKind.GEIQ:
geiq_eligibility_diagnosis = _get_geiq_eligibility_diagnosis_for_company(job_application)
geiq_eligibility_diagnosis = (
job_application.to_company.kind == CompanyKind.GEIQ
and _get_geiq_eligibility_diagnosis(job_application, only_prescriber=False)
)

context = {
"can_view_personal_information": request.user.can_view_personal_information(job_application.job_seeker),
Expand Down Expand Up @@ -141,10 +145,11 @@ def details_for_company(request, job_application_id, template_name="apply/proces
)

back_url = get_safe_url(request, "back_url", fallback_url=reverse_lazy("apply:list_for_siae"))
geiq_eligibility_diagnosis = None

if job_application.to_company.kind == CompanyKind.GEIQ:
geiq_eligibility_diagnosis = _get_geiq_eligibility_diagnosis_for_company(job_application)
geiq_eligibility_diagnosis = (
job_application.to_company.kind == CompanyKind.GEIQ
and _get_geiq_eligibility_diagnosis(job_application, only_prescriber=False)
)

context = {
"can_view_personal_information": True, # SIAE members have access to personal info
Expand Down Expand Up @@ -206,10 +211,7 @@ def details_for_prescriber(request, job_application_id, template_name="apply/pro
# Latest GEIQ diagnosis for this job seeker created by a *prescriber*
geiq_eligibility_diagnosis = (
job_application.to_company.kind == CompanyKind.GEIQ
and GEIQEligibilityDiagnosis.objects.valid()
.filter(job_seeker=job_application.job_seeker, author_prescriber_organization__isnull=False)
.select_related("author", "author_geiq", "author_prescriber_organization")
.first()
and _get_geiq_eligibility_diagnosis(job_application, only_prescriber=True)
)

# Refused applications information is providen to prescribers
Expand Down Expand Up @@ -682,7 +684,7 @@ def delete_prior_action(request, job_application_id, prior_action_id):
# GEIQ cannot require IAE eligibility diagnosis, but shared templates need this variable.
"eligibility_diagnosis_by_siae_required": False,
"geiq_eligibility_diagnosis": (
_get_geiq_eligibility_diagnosis_for_company(job_application)
_get_geiq_eligibility_diagnosis(job_application, only_prescriber=False)
if job_application.to_company.kind == CompanyKind.GEIQ
else None
),
Expand Down Expand Up @@ -751,7 +753,7 @@ def add_or_modify_prior_action(request, job_application_id, prior_action_id=None
form.save()
geiq_eligibility_diagnosis = None
if state_update and job_application.to_company.kind == CompanyKind.GEIQ:
geiq_eligibility_diagnosis = _get_geiq_eligibility_diagnosis_for_company(job_application)
geiq_eligibility_diagnosis = _get_geiq_eligibility_diagnosis(job_application, only_prescriber=False)
return render(
request,
"apply/includes/job_application_prior_action.html",
Expand Down
5 changes: 3 additions & 2 deletions tests/companies/factories.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import functools
import string

import factory.fuzzy
Expand Down Expand Up @@ -174,7 +173,9 @@ class CompanyWith4MembershipsFactory(CompanyFactory):
membership4 = factory.RelatedFactory(CompanyMembershipFactory, "company", is_admin=False, user__is_active=False)


CompanyWithMembershipAndJobsFactory = functools.partial(CompanyFactory, with_membership=True, with_jobs=True)
class CompanyWithMembershipAndJobsFactory(CompanyFactory):
with_membership = True
with_jobs = True


class SiaeConventionPendingGracePeriodFactory(SiaeConventionFactory):
Expand Down
6 changes: 5 additions & 1 deletion tests/eligibility/factories.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import random

import factory
from dateutil.relativedelta import relativedelta
from django.utils import timezone

from itou.companies.enums import CompanyKind
Expand All @@ -23,7 +24,10 @@ class Params:
),
author=factory.LazyAttribute(lambda obj: obj.author_prescriber_organization.members.first()),
)
expired = factory.Trait(expires_at=factory.LazyFunction(timezone.now))
expired = factory.Trait(
expires_at=factory.LazyFunction(timezone.now),
created_at=factory.LazyAttribute(lambda obj: obj.expires_at - relativedelta(months=6)),
)

created_at = factory.LazyFunction(timezone.now)
job_seeker = factory.SubFactory(JobSeekerFactory)
Expand Down
27 changes: 3 additions & 24 deletions tests/eligibility/test_geiq.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from django.core.exceptions import ValidationError
from django.db import IntegrityError, transaction
from django.db.models import Max
from django.utils import timezone

from itou.companies.enums import CompanyKind
from itou.eligibility.enums import AdministrativeCriteriaAnnex, AdministrativeCriteriaLevel
Expand Down Expand Up @@ -220,7 +219,7 @@ def test_geiq_administrative_criteria_validation(
GEIQ_ALLOWANCE_AMOUNT_814 = 814


def test_geiq_eligibility_diagnosis_allowance_and_eligibility(
def test_geiq_eligibility_diagnosis_allowance(
administrative_criteria_annex_1,
administrative_criteria_annex_2_level_1,
administrative_criteria_annex_2_level_2,
Expand All @@ -230,66 +229,46 @@ def test_geiq_eligibility_diagnosis_allowance_and_eligibility(
annex=AdministrativeCriteriaAnnex.ANNEX_2,
level=AdministrativeCriteriaLevel.LEVEL_2,
)[:2]
diagnosis = GEIQEligibilityDiagnosisFactory(from_prescriber=True)

# Prescriber author gets it all
assert diagnosis.eligibility_confirmed
diagnosis = GEIQEligibilityDiagnosisFactory(from_prescriber=True)
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_1400

diagnosis = GEIQEligibilityDiagnosisFactory(from_geiq=True)

assert not diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == 0

diagnosis.administrative_criteria.add(a2l2_crits[0])

# One A2L2 is not enough
assert not diagnosis.eligibility_confirmed
diagnosis.administrative_criteria.add(a2l2_crits[0])
assert diagnosis.allowance_amount == 0

# Two is ok
diagnosis.administrative_criteria.add(a2l2_crits[1])
assert diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_1400

# One L1 is enough to get max allowance
diagnosis = GEIQEligibilityDiagnosisFactory(from_geiq=True)
diagnosis.administrative_criteria.add(administrative_criteria_annex_2_level_1)

assert diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_1400

diagnosis = GEIQEligibilityDiagnosisFactory(from_geiq=True)
diagnosis.administrative_criteria.add(administrative_criteria_annex_1)

assert diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_814

# Adding another criteria will max allowance
diagnosis.administrative_criteria.add(administrative_criteria_annex_2_level_1)

assert diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_1400

# Special case of dual-annex criteria:

# Counts as Annex 1 criterion...
diagnosis = GEIQEligibilityDiagnosisFactory(from_geiq=True)
diagnosis.administrative_criteria.add(administrative_criteria_both_annexes)

assert diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_814

# ... and also as Annex 2 Level 2 criterion
diagnosis.administrative_criteria.add(administrative_criteria_annex_2_level_2)

assert diagnosis.eligibility_confirmed
assert diagnosis.allowance_amount == GEIQ_ALLOWANCE_AMOUNT_1400

# GEIQ eligibility is not confirmed with valid criteria and expired diagnosis
diagnosis = GEIQEligibilityDiagnosisFactory(from_prescriber=True, expires_at=timezone.now())
assert not diagnosis.eligibility_confirmed


def test_create_duplicate_diagnosis_in_same_geiq():
diagnosis = GEIQEligibilityDiagnosisFactory(from_geiq=True)
Expand Down
5 changes: 3 additions & 2 deletions tests/job_applications/factories.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
from itou.eligibility.enums import AuthorKind
from itou.job_applications import models
from itou.job_applications.enums import (
JobApplicationState,
Prequalification,
ProfessionalSituationExperience,
SenderKind,
Expand Down Expand Up @@ -65,8 +66,8 @@ class Params:
eligibility_diagnosis=None,
)
with_geiq_eligibility_diagnosis_from_prescriber = factory.Trait(
sent_by_authorized_prescriber_organisation=True,
to_company=factory.SubFactory(CompanyFactory, with_membership=True, kind=CompanyKind.GEIQ),
sender=factory.LazyAttribute(lambda obj: obj.sender_prescriber_organization.members.first()),
geiq_eligibility_diagnosis=factory.SubFactory(
GEIQEligibilityDiagnosisFactory,
job_seeker=factory.SelfAttribute("..job_seeker"),
Expand All @@ -91,7 +92,7 @@ class Params:
sender=factory.LazyAttribute(lambda obj: obj.sender_company.members.first()),
)
was_hired = factory.Trait(
state="accepted",
state=JobApplicationState.ACCEPTED,
to_company__with_jobs=True,
hired_job=factory.SubFactory(JobDescriptionFactory, company=factory.SelfAttribute("..to_company")),
)
Expand Down
Loading