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

feat(france-travail): add rendez-vous-partenaire api webhooks for participation v2 #2497

Open
wants to merge 24 commits into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 13 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
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: 6 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,9 @@ CARNET_DE_BORD_URL=https://demo.carnetdebord.inclusion.beta.gouv.fr
CARNET_DE_BORD_API_SECRET=secret_api_token

DEPARTMENTS_WHERE_PARCOURS_DISABLED=44

# France Travail Recette
FRANCE_TRAVAIL_AUTH_URL=https://entreprise-r.ft-qvr.fr
FRANCE_TRAVAIL_API_URL=https://api-r.ft-qvr.io
FRANCE_TRAVAIL_CLIENT_ID=client_id
FRANCE_TRAVAIL_CLIENT_SECRET=client_secret
4 changes: 3 additions & 1 deletion .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ AGENT_CONNECT_CLIENT_SECRET=client_secret

# France Travail
FRANCE_TRAVAIL_AUTH_URL=https://somefakeauthurl.fr
FRANCE_TRAVAIL_RDV_API_URL=https://francetravailfakerdvurl.fr
FRANCE_TRAVAIL_API_URL=https://francetravailfakerdvurl.fr
FRANCE_TRAVAIL_CLIENT_ID=client_id
FRANCE_TRAVAIL_CLIENT_SECRET=client_secret

AGENT_SIGNATURE_KEY=bc995863-5c80-43a3-a31d-0da216e814a4
54 changes: 54 additions & 0 deletions app/clients/france_travail_client.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
class FranceTravailClient
def initialize(user: nil)
@user = user
end

def create_participation(payload:)
Faraday.post(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rendez-vous-partenaire/v1/rendez-vous",
payload.to_json,
request_headers
)
end

def update_participation(payload:)
Faraday.put(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rendez-vous-partenaire/v1/rendez-vous",
payload.to_json,
request_headers
)
end

def delete_participation(france_travail_id:)
Faraday.delete(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rendez-vous-partenaire/v1/rendez-vous/#{france_travail_id}",
Holist marked this conversation as resolved.
Show resolved Hide resolved
{},
request_headers
)
end

Holist marked this conversation as resolved.
Show resolved Hide resolved
def user_token(payload:)
Holist marked this conversation as resolved.
Show resolved Hide resolved
Faraday.post(
"#{ENV['FRANCE_TRAVAIL_API_URL']}/partenaire/rechercher-usager/v1/usagers/recherche",
payload.to_json,
request_headers
)
end

def request_headers
@user.present? ? user_request_headers : client_request_headers
end
Holist marked this conversation as resolved.
Show resolved Hide resolved

def user_request_headers
FranceTravailApi::BuildUserAuthenticatedHeaders.call(user: @user).headers
end

def client_request_headers
access_token = FranceTravailApi::RetrieveAccessToken.call.access_token

{
"Authorization" => "Bearer #{access_token}",
"Content-Type" => "application/json"
}
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
module OutgoingWebhooks
module FranceTravail
class LockedAndOrderedJobBase < ApplicationJob
include LockedAndOrderedJobs

def self.job_timestamp(timestamp:, **)
timestamp
end
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module OutgoingWebhooks
module FranceTravail
class ProcessParticipationJob < LockedAndOrderedJobBase
def self.lock_key(participation_id:, **)
"#{base_lock_key}:#{participation_id}"
end

def perform(participation_id:, timestamp:, event:)
call_service!(FranceTravailApi::ProcessParticipation, participation_id: participation_id, timestamp: timestamp,
event: event)
end
end
end
end
10 changes: 0 additions & 10 deletions app/jobs/outgoing_webhooks/send_france_travail_webhook_job.rb

This file was deleted.

29 changes: 29 additions & 0 deletions app/models/concerns/participation/france_travail_webhooks.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# For france travail the webhooks are specific, we have to adapt to FT specs as they could not
# implement a system integrating our webhooks, so we separated the two webhooks logic.
module Participation::FranceTravailWebhooks
extend ActiveSupport::Concern

included do
after_commit on: :create, if: -> { organisation.france_travail? } do
OutgoingWebhooks::FranceTravail::ProcessParticipationJob.perform_later(
participation_id: id, timestamp: created_at, event: :create
)
end

after_commit on: :update, if: -> { organisation.france_travail? } do
OutgoingWebhooks::FranceTravail::ProcessParticipationJob.perform_later(
participation_id: id, timestamp: updated_at, event: :update
)
end

around_destroy lambda { |participation, block|
if participation.organisation.france_travail?
OutgoingWebhooks::FranceTravail::ProcessParticipationJob.perform_later(
participation_id: participation.id, timestamp: Time.current, event: :delete
)
end

block.call
}
end
Holist marked this conversation as resolved.
Show resolved Hide resolved
end
91 changes: 0 additions & 91 deletions app/models/concerns/rdv/france_travail_webhooks.rb

This file was deleted.

96 changes: 96 additions & 0 deletions app/models/france_travail/participation_payload.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
module FranceTravail
class ParticipationPayload
def initialize(participation)
@participation = participation
end

# rubocop:disable Metrics/AbcSize
def to_h
Holist marked this conversation as resolved.
Show resolved Hide resolved
{
id: @participation.france_travail_id,
adresse: @participation.lieu&.address,
date: @participation.starts_at.to_datetime,
duree: @participation.duration_in_min,
information: @participation.motif.instruction_for_rdv,
initiateur: france_travail_initiateur,
libelleAdresse: @participation.organisation.name,
modaliteContact: france_travail_modalite,
motif: france_travail_motif,
organisme: {
code: france_travail_organisme_code,
emailContact: @participation.organisation.email,
idStructure: @participation.organisation.safir_code,
libelleStructure: @participation.organisation.name,
telephoneContact: @participation.organisation.phone_number
},
statut: france_travail_statut,
telephoneContactUsager: @participation.user.phone_number,
theme: @participation.motif.name,
typeReception: france_travail_type_reception,
# agents.first est ok dans notre contexte ?
Holist marked this conversation as resolved.
Show resolved Hide resolved
interlocuteur: {
email: @participation.agents.first.email,
nom: @participation.agents.first.last_name,
prenom: @participation.agents.first.first_name
}
}
end
# rubocop:enable Metrics/AbcSize

# Liste des modalités FT (on ne prend en compte que le physique et le telephone): PHYSIQUE, TELEPHONE, VISIO
def france_travail_modalite
@participation.by_phone? ? "TELEPHONE" : "PHYSIQUE"
end

# Liste des initiateurs FT : USAGER, PARTENAIRE
def france_travail_initiateur
@participation.created_by_user? ? "USAGER" : "PARTENAIRE"
end

# Liste des motifs FT : AUT, ACC, ORI
def france_travail_motif
# A confirmer avec FT et Amaury, on se base sur la catégorie de motif ou on met AUT tout le temps ?
case @participation.motif.motif_category&.motif_category_type
when "rsa_orientation"
"ORI"
when "rsa_accompagnement"
"ACC"
else
"AUT"
end
end

# Liste des codes organismes FT : IND, FT, CD, DCD, ML, CE
def france_travail_organisme_code
case @participation.organisation.organisation_type
when "conseil_departemental"
"CD"
when "france_travail"
"FT"
when "delegataire_rsa"
"DCD"
else
"IND"
end
end

# Liste des types de réception FT : COL, IND
def france_travail_type_reception
@participation.collectif? ? "COL" : "IND"
end

# Liste des statuts FT : PRIS, EFFECTUE, MODIFIE, ABSENT, ANNULE
def france_travail_statut
case @participation.status
when "seen"
"EFFECTUE"
when "excused", "revoked"
"ANNULE"
when "noshow"
"ABSENT"
else
"PRIS"
end
end
end
end
4 changes: 3 additions & 1 deletion app/models/participation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ class Participation < ApplicationRecord
include Notificable
include HasCurrentCategoryConfiguration
include RdvParticipationStatus
include Participation::FranceTravailWebhooks

belongs_to :rdv
belongs_to :follow_up
Expand All @@ -14,6 +15,7 @@ class Participation < ApplicationRecord

has_many :notifications, dependent: :destroy
has_many :follow_up_invitations, through: :follow_up, source: :invitations
has_many :agents, through: :rdv

has_one :organisation, through: :rdv

Expand All @@ -28,7 +30,7 @@ class Participation < ApplicationRecord

enum created_by: { agent: "agent", user: "user", prescripteur: "prescripteur" }, _prefix: :created_by

delegate :starts_at, :motif_name,
delegate :starts_at, :motif, :lieu, :collectif?, :by_phone?, :duration_in_min,
:rdv_solidarites_url, :rdv_solidarites_rdv_id, :instruction_for_rdv,
to: :rdv
delegate :department, :department_id, to: :organisation
Expand Down
1 change: 0 additions & 1 deletion app/models/rdv.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ class Rdv < ApplicationRecord
include Notificable
include RdvParticipationStatus
include WebhookDeliverable
include Rdv::FranceTravailWebhooks
include HasCurrentCategoryConfiguration

after_commit :notify_participations_to_users, on: :update, if: :should_notify_users?
Expand Down
3 changes: 0 additions & 3 deletions app/models/webhook_receipt.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,4 @@ class WebhookReceipt < ApplicationRecord
belongs_to :webhook_endpoint, optional: true

validates :resource_model, :resource_id, :timestamp, presence: true

# france travail webhooks are not linked to a webhook_endpoint
scope :france_travail, -> { where(webhook_endpoint_id: nil) }
end
Loading