diff --git a/config/settings/base.py b/config/settings/base.py index 672ba50935d..313438f9cc0 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -711,3 +711,4 @@ RDV_SOLIDARITES_TOKEN_EXPIRY = os.getenv("RDV_SOLIDARITES_TOKEN_EXPIRY", 86000) # Token expires after 24h (86400s) RDV_INSERTION_API_BASE_URL = os.getenv("RDV_INSERTION_API_BASE_URL") RDV_INSERTION_INVITE_HOLD_DURATION = datetime.timedelta(days=int(os.getenv("RDV_INSERTION_INVITE_HOLD_DAYS", 10))) +RDV_INSERTION_WEBHOOK_SECRET = os.getenv("RDV_INSERTION_WEBHOOK_SECRET") diff --git a/config/urls.py b/config/urls.py index 7023eaa9600..40546caa690 100644 --- a/config/urls.py +++ b/config/urls.py @@ -85,6 +85,7 @@ path("legal/terms/", TemplateView.as_view(template_name="static/legal/terms.html"), name="legal-terms"), path("", include("itou.www.security.urls")), path("gps/", include("itou.www.gps.urls")), + path("rdvi/", include("itou.www.rdv_insertion.urls")), path("staff/", include("itou.www.itou_staff_views.urls")), ] diff --git a/itou/companies/admin.py b/itou/companies/admin.py index 8ed70ccf7b7..650d6a9dec7 100644 --- a/itou/companies/admin.py +++ b/itou/companies/admin.py @@ -160,7 +160,7 @@ def export(self, request, queryset): "block_job_applications", "job_applications_blocked_at", "approvals_list", - "rdv_insertion_id", + "rdv_solidarites_id", ) }, ), diff --git a/itou/companies/migrations/0005_company_rdv_insertion_id.py b/itou/companies/migrations/0005_company_rdv_insertion_id.py index d47fd1a8e29..042ea5b6962 100644 --- a/itou/companies/migrations/0005_company_rdv_insertion_id.py +++ b/itou/companies/migrations/0005_company_rdv_insertion_id.py @@ -14,11 +14,11 @@ class Migration(migrations.Migration): name="rdv_insertion_id", field=models.IntegerField( blank=True, - error_messages={"unique": "Une entreprise avec cet ID d'organisation RDV-I existe déjà."}, + error_messages={"unique": "Une entreprise avec cet ID d'organisation RDV-S existe déjà."}, help_text="Permet d'initier la prise de RDV via RDV-I lorsque renseigné.", null=True, unique=True, - verbose_name="identifiant d'organisation RDV-I", + verbose_name="identifiant d'organisation RDV-S", ), ), ] diff --git a/itou/companies/migrations/0007_rename_rdv_insertion_id_company_rdv_solidarites_id.py b/itou/companies/migrations/0007_rename_rdv_insertion_id_company_rdv_solidarites_id.py new file mode 100644 index 00000000000..1bd37afd2cd --- /dev/null +++ b/itou/companies/migrations/0007_rename_rdv_insertion_id_company_rdv_solidarites_id.py @@ -0,0 +1,17 @@ +# Generated by Django 5.0.8 on 2024-08-15 19:10 + +from django.db import migrations + + +class Migration(migrations.Migration): + dependencies = [ + ("companies", "0006_alter_company_created_by_alter_company_insee_city_and_more"), + ] + + operations = [ + migrations.RenameField( + model_name="company", + old_name="rdv_insertion_id", + new_name="rdv_solidarites_id", + ), + ] diff --git a/itou/companies/models.py b/itou/companies/models.py index ad18617c82d..0757a96ac06 100644 --- a/itou/companies/models.py +++ b/itou/companies/models.py @@ -268,13 +268,13 @@ class Company(AddressMixin, OrganizationAbstract): verbose_name="score de recommandation (ratio de candidatures récentes vs nombre d'offres d'emploi)", null=True ) - rdv_insertion_id = models.IntegerField( - verbose_name="identifiant d'organisation RDV-I", + rdv_solidarites_id = models.IntegerField( + verbose_name="identifiant d'organisation RDV-S", blank=True, null=True, unique=True, help_text="Permet d'initier la prise de RDV via RDV-I lorsque renseigné.", - error_messages={"unique": "Une entreprise avec cet ID d'organisation RDV-I existe déjà."}, + error_messages={"unique": "Une entreprise avec cet ID d'organisation RDV-S existe déjà."}, ) # Use the generic relation to let NotificationSettings being collected on deletion diff --git a/itou/rdv_insertion/migrations/0001_initial.py b/itou/rdv_insertion/migrations/0001_initial.py index a359d907029..87d51fa8fcd 100644 --- a/itou/rdv_insertion/migrations/0001_initial.py +++ b/itou/rdv_insertion/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 5.0.7 on 2024-08-07 10:33 +# Generated by Django 5.0.8 on 2024-08-15 19:20 import uuid @@ -11,7 +11,7 @@ class Migration(migrations.Migration): initial = True dependencies = [ - ("companies", "0005_company_rdv_insertion_id"), + ("companies", "0007_rename_rdv_insertion_id_company_rdv_solidarites_id"), migrations.swappable_dependency(settings.AUTH_USER_MODEL), ] @@ -23,26 +23,13 @@ class Migration(migrations.Migration): ("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)), + ("rdv_solidarites_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=[ @@ -261,7 +248,8 @@ class Migration(migrations.Migration): verbose_name="état", ), ), - ("rdv_insertion_id", models.IntegerField(editable=False, unique=True)), + ("rdv_insertion_user_id", models.IntegerField(db_index=True, editable=False)), + ("rdv_insertion_id", models.IntegerField(editable=False, null=True, unique=True)), ( "appointment", models.ForeignKey( @@ -299,6 +287,24 @@ class Migration(migrations.Migration): verbose_name="participants", ), ), + 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)), + ("is_processed", models.BooleanField(default=False, editable=False)), + ], + options={ + "verbose_name": "événement du webhook RDV-I", + "verbose_name_plural": "événements du webhook RDV-I", + "indexes": [ + models.Index(models.F("body__data__id"), name="webhookevent_rdvi_id_idx"), + models.Index(models.F("body__meta__model"), name="webhookevent_rdvi_type_idx"), + ], + }, + ), migrations.AddConstraint( model_name="invitation", constraint=models.UniqueConstraint( diff --git a/itou/rdv_insertion/models.py b/itou/rdv_insertion/models.py index 51ca1e55eb9..5fce4840547 100644 --- a/itou/rdv_insertion/models.py +++ b/itou/rdv_insertion/models.py @@ -149,7 +149,8 @@ class Participation(models.Model): editable=False, ) status = models.CharField("état", default=Status.UNKNOWN, choices=Status.choices, editable=False) - rdv_insertion_id = models.IntegerField(unique=True, editable=False) + rdv_insertion_user_id = models.IntegerField(db_index=True, editable=False) + rdv_insertion_id = models.IntegerField(unique=True, null=True, editable=False) class Meta: verbose_name = "participation à un événement RDV-I" @@ -178,7 +179,7 @@ class Location(models.Model): name = models.CharField("nom", editable=False) address = models.CharField("adresse", editable=False) phone_number = models.CharField("téléphone", null=True, editable=False) - rdv_insertion_id = models.IntegerField(unique=True, editable=False) + rdv_solidarites_id = models.IntegerField(unique=True, editable=False) class Meta: verbose_name = "lieu d'un événement RDV-I" @@ -189,7 +190,20 @@ class WebhookEvent(models.Model): created_at = models.DateTimeField("créée le", auto_now_add=True) body = models.JSONField(editable=False) headers = models.JSONField(editable=False) + is_processed = models.BooleanField(default=False, editable=False) class Meta: verbose_name = "événement du webhook RDV-I" verbose_name_plural = "événements du webhook RDV-I" + indexes = [ + models.Index(models.F("body__data__id"), name="webhookevent_rdvi_id_idx"), + models.Index(models.F("body__meta__model"), name="webhookevent_rdvi_type_idx"), + ] + + @property + def for_appointment(self): + return self.body["meta"]["model"].lower() == "rdv" + + @property + def for_invitation(self): + return self.body["meta"]["model"].lower() == "invitation" diff --git a/itou/templates/apply/includes/list_job_applications.html b/itou/templates/apply/includes/list_job_applications.html index 86ace2dc1a9..c56656e187f 100644 --- a/itou/templates/apply/includes/list_job_applications.html +++ b/itou/templates/apply/includes/list_job_applications.html @@ -78,7 +78,7 @@ {% elif job_applications_list_kind is JobApplicationsListKind.RECEIVED %} - {% if request.current_organization.rdv_insertion_id %} + {% if request.current_organization.rdv_solidarites_id %} {% include "apply/includes/buttons/rdv_insertion_invite.html" with job_application=job_application for_detail=False %} {% endif %} Informations générales - {% if job_application.upcoming_appointments or request.current_organization.rdv_insertion_id %} + {% if job_application.upcoming_appointments or request.current_organization.rdv_solidarites_id %}