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

Première version de la prise de rdv par intégration #5006

Merged
merged 23 commits into from
Jan 29, 2025
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
73 changes: 71 additions & 2 deletions app/controllers/agents/rdv_plans_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class Agents::RdvPlansController < AgentAuthController
layout "application"
before_action :find_rdv_plan
before_action :redirect_to_rdv, if: -> { @rdv_plan.rdv.present? }, except: [:rdv]

def show
redirect_to edit_starts_at_agents_rdv_plan_path(@rdv_plan)
Expand All @@ -12,10 +13,73 @@ def edit_starts_at

def update_starts_at
@rdv_plan.update!(params.require(:rdv_plan).permit(:starts_at).merge(rdv_agent: current_agent))
redirect_to show_starts_at_agents_rdv_plan_path(@rdv_plan)
redirect_to edit_modalites_agents_rdv_plan_path(@rdv_plan)
end

def show_starts_at; end
def edit_modalites; end

def update_modalites
rdv_plan_params = params.require(:rdv_plan).permit(:starts_at, :modalite)

if @rdv_plan.update(rdv_plan_params)
redirect_to edit_motif_agents_rdv_plan_path(@rdv_plan)
else
render "edit_modalites"
end
end

def edit_motif
@motifs = current_agent.motifs.individuel.where(
organisation_id: current_agent.roles.select(:organisation_id),
location_type: @rdv_plan.location_type,
service: @rdv_plan.rdv_agent.services
)
if @motifs.count == 1
@rdv_plan.motif_id ||= @motifs.first.id
end
@rdv_plan.duration_in_minutes ||= @motifs.first.default_duration_in_min
end

def update_motif
rdv_plan_params = params.require(:rdv_plan).permit(:motif_id, :duration_in_minutes)

if @rdv_plan.update(rdv_plan_params)
redirect_to edit_user_agents_rdv_plan_path(@rdv_plan)
else
render "edit_motif_from_calendar"
end
end

def edit_user; end

def create_rdv
rdv_plan_params = params.require(:rdv_plan)

user_attributes = rdv_plan_params.require(:user).permit(:email, :phone_number)

# TODO: possible à mettre en commun ?
participation_attributes = if @rdv_plan.motif.visible_and_notified?
rdv_plan_params.require(:participation).permit(
:send_lifecycle_notifications, :send_reminder_notification
)
else
{ send_lifecycle_notifications: false, send_reminder_notification: false }
end

rdv = @rdv_plan.create_rdv(user_attributes:, participation_attributes:)

if rdv.valid?
flash[:success] = "Le rendez-vous a été créé."
redirect_to rdv_agents_rdv_plan_path(@rdv_plan)
else
flash[:error] = rdv.errors.full_messages.to_sentence
redirect_to edit_user_agents_rdv_plan_path(@rdv_plan)
end
end

def rdv
@rdv = @rdv_plan.rdv
end

private

Expand All @@ -24,6 +88,11 @@ def find_rdv_plan
authorize @rdv_plan, :edit?, policy_class: Agent::RdvPlanPolicy
end

def redirect_to_rdv
# TODO: ajouter un flash ici?
redirect_to rdv_agents_rdv_plan_path(@rdv_plan)
end

def pundit_user
current_agent
end
Expand Down
16 changes: 9 additions & 7 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,15 +29,17 @@ def alert_dsfr_class_for(alert)
end
end

def datetime_input(form, field, input_html: {})
def datetime_input(form, field, input_html: {}, options: {})
form.input(
field,
as: :string,
input_html: {
value: form.object.send(field)&.strftime("%d/%m/%Y %H:%M"),
data: { behaviour: "datetimepicker" },
autocomplete: "off",
}.deep_merge(input_html)
{
as: :string,
input_html: {
value: form.object.send(field)&.strftime("%d/%m/%Y %H:%M"),
data: { behaviour: "datetimepicker" },
autocomplete: "off",
}.deep_merge(input_html),
}.deep_merge(options)
)
end

Expand Down
41 changes: 41 additions & 0 deletions app/models/rdv_plan.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,47 @@ class RdvPlan < ApplicationRecord

validate :return_url_is_authorized

# TODO: mettre en commun avec les motifs et ajouter une validation de synchro
enum :location_type, { public_office: "public_office", phone: "phone", home: "home", visio: "visio" }

def modalite
if location_type == "public_office"
"#{location_type}-#{lieu&.id}"
else
location_type
end
end

def modalite=(modalite)
self.location_type, self.lieu_id = modalite.split("-")
end

def create_rdv(user_attributes:, participation_attributes:)
if user.encrypted_password.blank? # Pour mettre à jour l'email sans renvoyer de mail de confirmation
user.skip_confirmation_notification!
user.skip_reconfirmation!
end
user.update!(user_attributes)

rdv = Rdv.create(
agents: [rdv_agent],
participations: [Participation.new(participation_attributes.merge(user_id: user.id))],
motif: motif,
organisation: organisation,
lieu: lieu,
starts_at: starts_at,
created_by: planning_agent,
ends_at: starts_at + (duration_in_minutes || motif.default_duration_in_min).minutes
)

if rdv.persisted?
update(rdv: rdv)
Notifiers::RdvCreated.perform_with(rdv, planning_agent)
end

rdv
end

private

def return_url_is_authorized
Expand Down
2 changes: 1 addition & 1 deletion app/models/service.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ class Service < ApplicationRecord
validates :name, :short_name, presence: true, uniqueness: { case_sensitive: false }

# Scopes
default_scope { order(Arel.sql("unaccent(LOWER(name))")) }
default_scope { order(Arel.sql("unaccent(LOWER(services.name))")) }

## -

Expand Down
11 changes: 10 additions & 1 deletion app/policies/agent/rdv_plan_policy.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class Agent::RdvPlanPolicy < ApplicationPolicy
def create?
pundit_user == record.planning_agent
authorized_lieu && pundit_user == record.planning_agent
end
alias edit? create?

Expand All @@ -9,4 +9,13 @@ def resolve
scope.where(planning_agent: pundit_user)
end
end

private

# TODO: ajouter une spec pour ce cas
def authorized_lieu
return true unless record.lieu_id

Agent::LieuPolicy::Scope.new(pundit_user, Lieu.enabled).resolve.find_by(id: record.lieu_id).present?
end
end
48 changes: 48 additions & 0 deletions app/views/agents/rdv_plans/_modalites_field.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
- available_location_types = rdv_plan.rdv_agent.motifs.individuel.active.where(organisation_id: rdv_plan.rdv_agent.roles.select(:organisation_id)).pluck(:location_type)

fieldset[class="fr-fieldset" id="rdv_plan[modalite]" aria-labelledby="radio-rich-no-pictogram-inline-legend radio-rich-no-pictogram-inline-messages"]
legend[class="fr-fieldset__legend--regular fr-fieldset__legend" id="radio-rich-no-pictogram-inline-legend"]
| Comment souhaitez-vous faire le rendez-vous ?

- if available_location_types.include?("public_office")
- lieux = policy_scope(Lieu.enabled, policy_scope_class: Agent::LieuPolicy::Scope)
- lieux.each do |lieu|
.fr-fieldset__element
.fr-radio-group.fr-radio-rich
input[value="public_office-#{lieu.id}" type="radio" id="public_office-#{lieu.id}" name="rdv_plan[modalite]" required]
label.fr-label[for="public_office-#{lieu.id}"]
span
= lieu_icon
= " Sur place à #{lieu.name}"
span.fr-hint-text = lieu.address

- if available_location_types.include?("phone")
.fr-fieldset__element
.fr-radio-group.fr-radio-rich
input[value="phone" type="radio" id="rdv_plan_modalite_phone" name="rdv_plan[modalite]" required]
label.fr-label[for="rdv_plan_modalite_phone"]
span
= phone_icon
= " Par téléphone"

- if available_location_types.include?("visio")
.fr-fieldset__element
.fr-radio-group.fr-radio-rich
input[value="visio" type="radio" id="rdv_plan_modalite_visio" name="rdv_plan[modalite]" required]
label.fr-label[for="rdv_plan_modalite_visio"]
span
= visio_icon
= " Par visioconférence"
span.fr-hint-text
| Nous vous fournirons un lien de visio

- if available_location_types.include?("home")
.fr-fieldset__element
.fr-radio-group.fr-radio-rich
input[value="home" type="radio" id="rdv_plan_modalite_home" name="rdv_plan[modalite]" required]
label.fr-label[for="rdv_plan_modalite_home"]
span
= home_icon
| Au domicile de l'usager

div[class="fr-messages-group" id="radio-rich-no-pictogram-inline-messages" aria-live="polite"]
18 changes: 18 additions & 0 deletions app/views/agents/rdv_plans/edit_modalites.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.fr-row
.fr-col-12
= render "agents/rdv_plans/header", rdv_plan: @rdv_plan, current_step: 1, step_title: "Créneau", next_step_title: "Motif"
.row.fr-mb-16w
.col-12.col-md-4
= render "agents/rdv_plans/calendar", rdv_plan: @rdv_plan, single_day: true
= link_to edit_starts_at_agents_rdv_plan_path(@rdv_plan) do
= "retour"

.col-12.col-md-4
= simple_form_for @rdv_plan, url: update_modalites_agents_rdv_plan_path(@rdv_plan) do |f|
.fr-mb-4w
.input-group
= datetime_input(f, :starts_at, options: { label_html: { style: "flex-shrink: 0;", class: "fr-mr-2w" }, wrapper_html: { class: "d-flex", style: "align-items: baseline;" }})

= render "agents/rdv_plans/modalites_field", rdv_plan: @rdv_plan

= f.submit "Continuer", class: "fr-btn float-right"
23 changes: 23 additions & 0 deletions app/views/agents/rdv_plans/edit_motif.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.fr-row
.fr-col-12
= render "agents/rdv_plans/header", rdv_plan: @rdv_plan, current_step: 2, step_title: "Motif", next_step_title: "Usager"
.row.fr-mb-16w
.col-4
= render "agents/rdv_plans/calendar", rdv_plan: @rdv_plan, single_day: true
= link_to edit_modalites_agents_rdv_plan_path(@rdv_plan) do
= back_icon(class: "fr-mr-1w")
= "retour"

.col-12.col-md-6
= render "agents/rdv_plans/summary/starts_at", rdv_plan: @rdv_plan
= render "agents/rdv_plans/summary/location_type", rdv_plan: @rdv_plan
hr.fr-mt-2w.fr-mb-4w

= simple_form_for @rdv_plan, url: update_motif_agents_rdv_plan_path(@rdv_plan) do |f|
= render "model_errors", model: @rdv_plan

.input-group.fr-mb-3w
= f.input :motif_id, label: "Motif du rendez-vous", required: true, collection: @motifs, label_method: :name, label_html: { class: "fr-mr-2w" }, include_blank: true

= f.input :duration_in_minutes, label: "Durée en minutes"
= f.submit "Continuer", class: "fr-btn float-right"
31 changes: 31 additions & 0 deletions app/views/agents/rdv_plans/edit_user.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
.row.justify-content-md-center
.col-12
= render "agents/rdv_plans/header", rdv_plan: @rdv_plan, current_step: 3, step_title: "Usager", next_step_title: ""
.row.fr-mb-16w
.col-12.col-md-4
= render "agents/rdv_plans/calendar", rdv_plan: @rdv_plan, single_day: true
= link_to edit_motif_agents_rdv_plan_path(@rdv_plan) do
= back_icon(class: "fr-mr-1w")
= "retour"
.col-12.col-md-8
= render "agents/rdv_plans/summary/starts_at", rdv_plan: @rdv_plan
= render "agents/rdv_plans/summary/location_type", rdv_plan: @rdv_plan
= render "agents/rdv_plans/summary/motif", rdv_plan: @rdv_plan

hr.fr-mt-2w
h3= @rdv_plan.user.full_name
= simple_form_for @rdv_plan, url: create_rdv_agents_rdv_plan_path(@rdv_plan), method: :post do |f|
= f.fields_for :user, @rdv_plan.user do |ff|
.row
.col-6
/ TODO: gérer le cas des users confirmed (et gérer ce cas dans l'interface principale aussi) : leur nouvelle adresse mail ne sera pas prise en compte tant qu'ils ne la confirment pas
= ff.input :email
.col-6
= ff.input :phone_number
- if @rdv_plan.motif.visible_and_notified?
= f.fields_for :participation, (Participation.new(send_lifecycle_notifications: true, send_reminder_notification: true)) do |ff|
= ff.input :send_lifecycle_notifications, label: "Envoyer une notification de confirmation"
= ff.input :send_reminder_notification, label: "Envoyer une notification de rappel 48h avant le rendez-vous"
- else
| Les notifications ne sont pas envoyées pour ce motif de rendez-vous.
= f.submit "Confirmer le rendez-vous", class: "fr-btn float-right fr-btn--lg"
33 changes: 33 additions & 0 deletions app/views/agents/rdv_plans/rdv.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
.fr-grid-row.justify-content-md-center.fr-mb-16w
.fr-col-8
h1.fr-h2 Rendez-vous confirmé
.card
.card-body
div
span.fr-icon-calendar-fill.fr-mr-1w[aria-hidden="true"]
= "#{l(@rdv.starts_at, format: :human)} (#{@rdv.duration_in_min} minutes)"
= " "
= dsfr_link_to "voir dans l'agenda", admin_organisation_agent_agenda_path(@rdv.organisation, @rdv.agents.first, selected_event_id: @rdv.id, date: @rdv.starts_at.to_date), target: :blank

.fr-mt-2w
- if @rdv.lieu
= lieu_icon(class: "fr-mr-1w")
= @rdv.lieu.name
br
.fr-ml-4w= @rdv.lieu.address
/ TODO: gérer les autres location types

.fr-mt-2w
= motif_icon(class: "fr-mr-1w")
= "Motif : #{@rdv.motif.name}"

.fr-mt-2w
span.fr-icon-user-fill.fr-mr-1w[aria-hidden="true"]
= @rdv_plan.user.full_name
.fr-ml-4w= @rdv_plan.user.email
.fr-ml-4w= @rdv_plan.user.phone_number

.fr-mt-4w
= link_to "Modifier", edit_admin_organisation_rdv_path(@rdv.organisation, @rdv), class: "fr-btn fr-btn--secondary", target: :blank
- if @rdv_plan.return_url
= link_to "Retour sur Mon Suivi Social", @rdv_plan.return_url, class: "float-right"
12 changes: 12 additions & 0 deletions app/views/agents/rdv_plans/summary/_location_type.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/ locals(rdv_plan:)
br
- if rdv_plan.public_office?
= lieu_icon(class: "fr-mr-1w")
= rdv_plan.lieu.name
- elsif rdv_plan.phone?
= phone_icon(class: "fr-mr-1w")
= "Par téléphone"
- elsif rdv_plan.visio?
= visio_icon(class: "fr-mr-1w")
= "Par visio"
= link_to "modifier", edit_modalites_agents_rdv_plan_path(rdv_plan), class: "fr-ml-2w"
5 changes: 5 additions & 0 deletions app/views/agents/rdv_plans/summary/_motif.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/ locals(rdv_plan:)
br
= motif_icon(class: "fr-mr-1w")
= rdv_plan.motif.name
= link_to "modifier", edit_motif_agents_rdv_plan_path(rdv_plan), class: "fr-ml-2w"
4 changes: 4 additions & 0 deletions app/views/agents/rdv_plans/summary/_starts_at.html.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/ locals(rdv_plan:)
span.fr-icon-calendar-fill.fr-mr-1w[aria-hidden="true"]
= "#{l(rdv_plan.starts_at, format: :human)} (#{rdv_plan.duration_in_minutes} minutes)"
= link_to "modifier", edit_starts_at_agents_rdv_plan_path(rdv_plan), class: "fr-ml-2w"
1 change: 1 addition & 0 deletions config/anonymizer.yml
Original file line number Diff line number Diff line change
Expand Up @@ -457,3 +457,4 @@ tables:
- starts_at
- created_at
- updated_at
- location_type
Loading
Loading