Skip to content

Commit

Permalink
feat(rdvi): add RDV-I appointment details for companies
Browse files Browse the repository at this point in the history
  • Loading branch information
leo-naeka committed Sep 13, 2024
1 parent d29ed17 commit bc7a39a
Show file tree
Hide file tree
Showing 25 changed files with 2,396 additions and 309 deletions.
20 changes: 20 additions & 0 deletions itou/rdv_insertion/api.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,22 @@
import logging
from urllib.parse import urljoin

import httpx
from django.conf import settings
from django.core.cache import cache
from django.core.exceptions import ImproperlyConfigured

from .enums import InvitationStatus


logger = logging.getLogger(__name__)


RDV_S_CREDENTIALS_CACHE_KEY = "rdv-solidarites-credentials"

RDV_I_INVITATION_DELIVERED_STATUSES = ["delivered"]
RDV_I_INVITATION_NOT_DELIVERED_STATUSES = ["soft_bounce", "hard_bounce", "blocked", "invalid_email", "error"]


def get_api_credentials(refresh=False):
"""
Expand Down Expand Up @@ -37,3 +46,14 @@ def get_api_credentials(refresh=False):
raise ImproperlyConfigured(
"RDV-S settings must be set: RDV_SOLIDARITES_API_BASE_URL, RDV_SOLIDARITES_EMAIL, RDV_SOLIDARITES_PASSWORD"
)


def get_invitation_status(invitation_dict):
if invitation_dict.get("clicked"):
return InvitationStatus.OPENED
if delivery_status := invitation_dict.get("delivery_status"):
if delivery_status in RDV_I_INVITATION_DELIVERED_STATUSES:
return InvitationStatus.DELIVERED
if delivery_status in RDV_I_INVITATION_NOT_DELIVERED_STATUSES:
return InvitationStatus.NOT_DELIVERED
logger.error(f"Invalid RDV-I invitation status: '{delivery_status}' not in supported list")
39 changes: 39 additions & 0 deletions itou/rdv_insertion/enums.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,43 @@ class InvitationType(models.TextChoices):
class InvitationStatus(models.TextChoices):
SENT = "sent", "Envoyée"
DELIVERED = "delivered", "Délivrée"
NOT_DELIVERED = "not_delivered", "Non délivrée"
OPENED = "opened", "Ouverte"


class ParticipationStatus(models.TextChoices):
UNKNOWN = "unknown", "Non déterminé"
SEEN = "seen", "RDV honoré"
EXCUSED = "excused", "RDV annulé à l’initiative de l’usager"
REVOKED = "revoked", "RDV annulé à l’initiative du service"
NOSHOW = "noshow", "Absence non excusée au RDV"


class InvitationRequestReasonCategory(models.TextChoices):
RSA_DROITS_DEVOIRS = "rsa_droits_devoirs", "RSA - droits et devoirs"
RSA_ORIENTATION = "rsa_orientation", "RSA orientation"
RSA_ORIENTATION_FRANCE_TRAVAIL = "rsa_orientation_france_travail", "RSA orientation France Travail"
RSA_ACCOMPAGNEMENT = "rsa_accompagnement", "RSA accompagnement"
RSA_ACCOMPAGNEMENT_SOCIAL = "rsa_accompagnement_social", "RSA accompagnement social"
RSA_ACCOMPAGNEMENT_SOCIOPRO = "rsa_accompagnement_sociopro", "RSA accompagnement socio-pro"
RSA_ORIENTATION_ON_PHONE_PLATFORM = (
"rsa_orientation_on_phone_platform",
"RSA orientation sur plateforme téléphonique",
)
RSA_CER_SIGNATURE = "rsa_cer_signature", "RSA signature CER"
RSA_INSERTION_OFFER = "rsa_insertion_offer", "RSA offre insertion pro"
RSA_FOLLOW_UP = "rsa_follow_up", "RSA suivi"
RSA_MAIN_TENDUE = "rsa_main_tendue", "RSA Main Tendue"
RSA_ATELIER_COLLECTIF_MANDATORY = "rsa_atelier_collectif_mandatory", "RSA Atelier collectif"
RSA_SPIE = "rsa_spie", "RSA SPIE"
RSA_INTEGRATION_INFORMATION = "rsa_integration_information", "RSA Information d'intégration"
RSA_ATELIER_COMPETENCES = "rsa_atelier_competences", "RSA Atelier compétences"
RSA_ATELIER_RENCONTRES_PRO = "rsa_atelier_rencontres_pro", "RSA Atelier rencontres professionnelles"
PSYCHOLOGUE = "psychologue", "Psychologue"
RSA_ORIENTATION_FREELANCE = "rsa_orientation_freelance", "RSA orientation - travailleurs indépendants"
RSA_ORIENTATION_COACHING = "rsa_orientation_coaching", "RSA orientation - coaching emploi"
ATELIER_ENFANTS_ADOS = "atelier_enfants_ados", "Atelier Enfants / Ados"
RSA_ORIENTATION_FILE_ACTIVE = "rsa_orientation_file_active", "RSA orientation file active"
SIAE_INTERVIEW = "siae_interview", "Entretien SIAE"
SIAE_COLLECTIVE_INFORMATION = "siae_collective_information", "Info coll. SIAE"
SIAE_FOLLOW_UP = "siae_follow_up", "Suivi SIAE"
224 changes: 221 additions & 3 deletions itou/rdv_insertion/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 5.0.6 on 2024-07-02 17:04
# Generated by Django 5.0.7 on 2024-08-07 10:33

import uuid

Expand All @@ -16,10 +16,69 @@ class Migration(migrations.Migration):
]

operations = [
migrations.CreateModel(
name="Location",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
("name", models.CharField(editable=False, verbose_name="nom")),
("address", models.CharField(editable=False, verbose_name="adresse")),
("phone_number", models.CharField(editable=False, null=True, verbose_name="téléphone")),
("rdv_insertion_id", models.IntegerField(editable=False, unique=True)),
],
options={
"verbose_name": "lieu d'un événement RDV-I",
"verbose_name_plural": "lieux d'événements RDV-I",
},
),
migrations.CreateModel(
name="WebhookEvent",
fields=[
("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")),
("created_at", models.DateTimeField(auto_now_add=True, verbose_name="créée le")),
("body", models.JSONField(editable=False)),
("headers", models.JSONField(editable=False)),
],
options={
"verbose_name": "événement du webhook RDV-I",
"verbose_name_plural": "événements du webhook RDV-I",
},
),
migrations.CreateModel(
name="InvitationRequest",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
(
"reason_category",
models.CharField(
choices=[
("rsa_droits_devoirs", "RSA - droits et devoirs"),
("rsa_orientation", "RSA orientation"),
("rsa_orientation_france_travail", "RSA orientation France Travail"),
("rsa_accompagnement", "RSA accompagnement"),
("rsa_accompagnement_social", "RSA accompagnement social"),
("rsa_accompagnement_sociopro", "RSA accompagnement socio-pro"),
("rsa_orientation_on_phone_platform", "RSA orientation sur plateforme téléphonique"),
("rsa_cer_signature", "RSA signature CER"),
("rsa_insertion_offer", "RSA offre insertion pro"),
("rsa_follow_up", "RSA suivi"),
("rsa_main_tendue", "RSA Main Tendue"),
("rsa_atelier_collectif_mandatory", "RSA Atelier collectif"),
("rsa_spie", "RSA SPIE"),
("rsa_integration_information", "RSA Information d'intégration"),
("rsa_atelier_competences", "RSA Atelier compétences"),
("rsa_atelier_rencontres_pro", "RSA Atelier rencontres professionnelles"),
("psychologue", "Psychologue"),
("rsa_orientation_freelance", "RSA orientation - travailleurs indépendants"),
("rsa_orientation_coaching", "RSA orientation - coaching emploi"),
("atelier_enfants_ados", "Atelier Enfants / Ados"),
("rsa_orientation_file_active", "RSA orientation file active"),
("siae_interview", "Entretien SIAE"),
("siae_collective_information", "Info coll. SIAE"),
("siae_follow_up", "Suivi SIAE"),
],
verbose_name="catégorie de motif",
),
),
("created_at", models.DateTimeField(auto_now_add=True, verbose_name="créée le")),
("api_response", models.JSONField(editable=False)),
("rdv_insertion_user_id", models.IntegerField(db_index=True, editable=False)),
Expand Down Expand Up @@ -61,12 +120,18 @@ class Migration(migrations.Migration):
(
"status",
models.CharField(
choices=[("sent", "Envoyée"), ("delivered", "Délivrée"), ("opened", "Ouverte")],
choices=[
("sent", "Envoyée"),
("delivered", "Délivrée"),
("not_delivered", "Non délivrée"),
("opened", "Ouverte"),
],
default="sent",
verbose_name="état",
),
),
("rdv_insertion_invitation_id", models.IntegerField(editable=False, unique=True)),
("delivered_at", models.DateTimeField(editable=False, null=True, verbose_name="délivrée le")),
("rdv_insertion_id", models.IntegerField(editable=False, unique=True)),
(
"invitation_request",
models.ForeignKey(
Expand All @@ -82,6 +147,159 @@ class Migration(migrations.Migration):
"verbose_name_plural": "invitations RDV-I",
},
),
migrations.CreateModel(
name="Appointment",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
(
"status",
models.CharField(
choices=[
("unknown", "Non déterminé"),
("seen", "RDV honoré"),
("excused", "RDV annulé à l’initiative de l’usager"),
("revoked", "RDV annulé à l’initiative du service"),
("noshow", "Absence non excusée au RDV"),
],
default="unknown",
editable=False,
verbose_name="état",
),
),
(
"reason_category",
models.CharField(
choices=[
("rsa_droits_devoirs", "RSA - droits et devoirs"),
("rsa_orientation", "RSA orientation"),
("rsa_orientation_france_travail", "RSA orientation France Travail"),
("rsa_accompagnement", "RSA accompagnement"),
("rsa_accompagnement_social", "RSA accompagnement social"),
("rsa_accompagnement_sociopro", "RSA accompagnement socio-pro"),
("rsa_orientation_on_phone_platform", "RSA orientation sur plateforme téléphonique"),
("rsa_cer_signature", "RSA signature CER"),
("rsa_insertion_offer", "RSA offre insertion pro"),
("rsa_follow_up", "RSA suivi"),
("rsa_main_tendue", "RSA Main Tendue"),
("rsa_atelier_collectif_mandatory", "RSA Atelier collectif"),
("rsa_spie", "RSA SPIE"),
("rsa_integration_information", "RSA Information d'intégration"),
("rsa_atelier_competences", "RSA Atelier compétences"),
("rsa_atelier_rencontres_pro", "RSA Atelier rencontres professionnelles"),
("psychologue", "Psychologue"),
("rsa_orientation_freelance", "RSA orientation - travailleurs indépendants"),
("rsa_orientation_coaching", "RSA orientation - coaching emploi"),
("atelier_enfants_ados", "Atelier Enfants / Ados"),
("rsa_orientation_file_active", "RSA orientation file active"),
("siae_interview", "Entretien SIAE"),
("siae_collective_information", "Info coll. SIAE"),
("siae_follow_up", "Suivi SIAE"),
],
editable=False,
verbose_name="catégorie de motif",
),
),
("reason", models.CharField(editable=False, verbose_name="motif")),
("is_collective", models.BooleanField(editable=False, verbose_name="rendez-vous collectif")),
("start_at", models.DateTimeField(editable=False, verbose_name="commence le")),
("duration", models.DurationField(editable=False, verbose_name="durée")),
("canceled_at", models.DateTimeField(editable=False, null=True, verbose_name="annulé le")),
("address", models.CharField(editable=False, verbose_name="adresse")),
(
"total_participants",
models.PositiveSmallIntegerField(editable=False, null=True, verbose_name="nombre de participants"),
),
(
"max_participants",
models.PositiveSmallIntegerField(
editable=False, null=True, verbose_name="nombre max. de participants"
),
),
("rdv_insertion_id", models.IntegerField(editable=False, unique=True)),
(
"company",
models.ForeignKey(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="rdvi_appointments",
to="companies.company",
verbose_name="entreprise",
),
),
(
"location",
models.ForeignKey(
editable=False,
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="rdvi_appointments",
to="rdv_insertion.location",
verbose_name="lieu",
),
),
],
options={
"verbose_name": "rendez-vous RDV-I",
"verbose_name_plural": "rendez-vous RDV-I",
},
),
migrations.CreateModel(
name="Participation",
fields=[
("id", models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
(
"status",
models.CharField(
choices=[
("unknown", "Non déterminé"),
("seen", "RDV honoré"),
("excused", "RDV annulé à l’initiative de l’usager"),
("revoked", "RDV annulé à l’initiative du service"),
("noshow", "Absence non excusée au RDV"),
],
default="unknown",
editable=False,
verbose_name="état",
),
),
("rdv_insertion_id", models.IntegerField(editable=False, unique=True)),
(
"appointment",
models.ForeignKey(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="rdvi_participations",
to="rdv_insertion.appointment",
verbose_name="rendez-vous",
),
),
(
"job_seeker",
models.ForeignKey(
editable=False,
on_delete=django.db.models.deletion.CASCADE,
related_name="rdvi_participations",
to=settings.AUTH_USER_MODEL,
verbose_name="demandeur d'emploi",
),
),
],
options={
"verbose_name": "participation à un événement RDV-I",
"verbose_name_plural": "participations aux événements RDV-I",
},
),
migrations.AddField(
model_name="appointment",
name="participants",
field=models.ManyToManyField(
editable=False,
related_name="rdvi_appointments",
through="rdv_insertion.Participation",
to=settings.AUTH_USER_MODEL,
verbose_name="participants",
),
),
migrations.AddConstraint(
model_name="invitation",
constraint=models.UniqueConstraint(
Expand Down
Loading

0 comments on commit bc7a39a

Please sign in to comment.