Skip to content

Commit

Permalink
Reopening an authorization with previous stages gives a choice
Browse files Browse the repository at this point in the history
  • Loading branch information
JeSuisUnCaillou committed Jan 21, 2025
1 parent 1fecc05 commit e423b34
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 10 deletions.
18 changes: 18 additions & 0 deletions app/assets/stylesheets/components/reopen_authorizations.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
.reopen-stage-buttons-container {
width: 100%;
display: flex;
align-items: flex-start;
}

.reopen-stage-buttons {
flex: 1;
display: flex;
flex-direction: column;
gap: 1rem;
}

.reopen-stage-cancel {
display: flex;
align-items: flex-end;
height: 100%;
}
14 changes: 13 additions & 1 deletion app/controllers/reopen_authorizations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
class ReopenAuthorizationsController < AuthenticatedUserController
before_action :extract_authorization
before_action :extract_authorization, :extract_authorization_request_class
before_action :authorize_authorization_reopening

def new; end
Expand All @@ -22,6 +22,7 @@ def reopen_authorization
ReopenAuthorization.call(
authorization: @authorization,
user: current_user,
authorization_request_class: @authorization_request_class
)
end

Expand All @@ -37,6 +38,17 @@ def extract_authorization
@authorization = authorization_request.authorizations.friendly.find(params[:authorization_id])
end

def extract_authorization_request_class
return if params[:authorization_request_class].blank?

request_classes_hash = AuthorizationDefinition.all_request_classes.to_h { |klass| [klass.to_s, klass] }
actual_authorization_request_class = request_classes_hash[params[:authorization_request_class]]

raise ActionController::UnpermittedParameters unless actual_authorization_request_class.present?

@authorization_request_class = actual_authorization_request_class
end

def authorize_authorization_reopening
authorize @authorization, :reopen?
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
class TransitionAuthorizationRequestToPreviousStage < ApplicationInteractor
def call
return if context.authorization_request_class.blank?

context.fail! unless context.authorization_request.can_reopen_to_class?(context.authorization_request_class)

return if context.authorization_request.is_a? context.authorization_request_class

transition_to_previous_stage
end

private

def transition_to_previous_stage
context.authorization_request.update!(
type: context.authorization_request_class.to_s,
form_uid: context.authorization_request.definition.previous_stage_form(context.authorization_request_class).id
)
end
end
4 changes: 4 additions & 0 deletions app/models/authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,10 @@ def definition
authorization_request_class.constantize.definition
end

def can_reopen_to_another_stage?
authorization_request.available_classes_for_reopen.count > 1
end

private

def affect_snapshot_documents(request_as_validated)
Expand Down
8 changes: 6 additions & 2 deletions app/models/authorization_definition.rb
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ def self.build(uid, hash)
end

def reopenable?
!next_stage?
true
end

def instructors
Expand Down Expand Up @@ -86,9 +86,13 @@ def startable_by_applicant
value_or_default(@startable_by_applicant, true)
end

delegate :next_stage_form, :next_stage_definition, :next_stage?, to: :stage
delegate :next_stage_form, :next_stage_definition, :next_stage?, :previous_stage_form, to: :stage

def authorization_request_class
@authorization_request_class ||= AuthorizationRequest.const_get(id.classify)
end

def self.all_request_classes
all.map(&:authorization_request_class)
end
end
4 changes: 4 additions & 0 deletions app/models/authorization_definition/stage.rb
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ def next_stage_form
next_stage_definition.available_forms.find { |form| form.id == next_stage[:form_id] } || raise(ActiveRecord::RecordNotFound, "Couln't find form with id #{next_stage[:form_id]}")
end

def previous_stage_form(authorization_request_class)
previous_stages.find { |previous| previous[:definition].authorization_request_class == authorization_request_class }&.fetch(:form)
end

def next_stage
@next || (raise NotExists)
end
Expand Down
8 changes: 8 additions & 0 deletions app/models/authorization_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,14 @@ def latest_authorization_of_class(authorization_request_class)
authorizations.where(authorization_request_class: authorization_request_class).order(created_at: :desc).limit(1).first
end

def available_classes_for_reopen
authorizations.distinct.pluck(:authorization_request_class).map(&:constantize)
end

def can_reopen_to_class?(authorization_request_class)
available_classes_for_reopen.include? authorization_request_class
end

def events
@events ||= AuthorizationRequestEventsQuery.new(self).perform
end
Expand Down
2 changes: 1 addition & 1 deletion app/organizers/reopen_authorization.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ class ReopenAuthorization < ApplicationOrganizer
context.authorization_request = context.authorization.request
end

organize ExecuteAuthorizationRequestTransitionWithCallbacks
organize TransitionAuthorizationRequestToPreviousStage, ExecuteAuthorizationRequestTransitionWithCallbacks
end
31 changes: 26 additions & 5 deletions app/views/reopen_authorizations/new.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -6,17 +6,38 @@
<h1 class="fr-modal__title">
<%= t('.title', authorization_name: @authorization.name) %>
</h1>

<p>
<%= t('.disclaimer').html_safe %>
</p>

<% if @authorization.can_reopen_to_another_stage? %>
<div class="fr-alert fr-alert--warning">
<h3 class="fr-alert__title"><%= t('.warning_for_stages.title') %></h3>
<p><%= t('.warning_for_stages.content').html_safe %>
</div>
<% end %>
</div>

<div class="fr-modal__footer">
<div class="fr-btns-group fr-btns-group--right fr-btns-group--inline-reverse fr-btns-group--inline-lg fr-btns-group--icon-left">
<%= link_to t('.cancel'), '#', class: %w(fr-btn fr-btn--secondary), aria: { controls: 'main-modal' } %>
<%= button_to t('.reopen'), url_for(controller: 'reopen_authorizations', action: 'create', authorization_request_id: @authorization.request_id, authorization_id: @authorization.id), class: %w(fr-btn fr-btn--primary fr-icon-success-line fr-btn--icon-left) %>
</div>
<% if @authorization.can_reopen_to_another_stage? %>
<div class="reopen-stage-buttons-container">
<div class="reopen-stage-buttons">
<% @authorization.request.available_classes_for_reopen.each do |authorization_request_class| %>
<%= button_to t(".reopen_to_stage.#{authorization_request_class.definition.stage.type}"), url_for(controller: 'reopen_authorizations', action: 'create', authorization_request_class:, authorization_request_id: @authorization.request_id, authorization_id: @authorization.id), class: "fr-btn fr-btn--primary fr-icon-success-line fr-btn--icon-left reopen-stage-button" %>
<% end %>
</div>

<div class="reopen-stage-cancel">
<%= link_to t('.cancel'), '#', class: %w(fr-btn fr-btn--secondary), aria: { controls: 'main-modal' } %>
</div>
</div>

<% else %>
<div class="fr-btns-group fr-btns-group--right fr-btns-group--inline fr-btns-group--inline-lg fr-btns-group--icon-left">
<%= button_to t('.reopen'), url_for(controller: 'reopen_authorizations', action: 'create', authorization_request_id: @authorization.request_id, authorization_id: @authorization.id), class: %w(fr-btn fr-btn--primary fr-icon-success-line fr-btn--icon-left) %>
<%= link_to t('.cancel'), '#', class: %w(fr-btn fr-btn--secondary), aria: { controls: 'main-modal' } %>
</div>
<% end %>
</div>
</turbo-frame>
</div>
Expand Down
2 changes: 1 addition & 1 deletion config/authorization_definitions.yml
Original file line number Diff line number Diff line change
Expand Up @@ -334,7 +334,7 @@ shared:
type: production
previouses:
- id: api_impot_particulier_sandbox
form_id: api-impot-particulier-production
form_id: api-impot-particulier-sandbox
blocks:
- name: basic_infos
- name: personal_data
Expand Down
6 changes: 6 additions & 0 deletions config/locales/fr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -444,8 +444,14 @@ fr:
<br />
<br />
Votre habilitation restera valide quelque soit l'issue de la demande de mise à jour.
warning_for_stages:
title: Vos mises à jour peuvent concerner votre habilitation bac à sable
content: "Pour savoir si les mises à jour que vous désirez effectuer nécessitent de passer d'abord par une mise à jour de l'habilitation bac à sable, contactez le fournisseur de données : <br /><a class=\"fr-link\" target=\"_blank\" href=\"mailto:[email protected]\">[email protected]</a>"
cancel: Annuler
reopen: Mettre à jour l'habilitation
reopen_to_stage:
sandbox: Mettre à jour l'habilitation bac à sable
production: Mettre à jour l'habilitation de production
create:
success:
title: L'habilitation %{name} a bien été réouverte
Expand Down
15 changes: 15 additions & 0 deletions features/reouverture_habilitation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -114,3 +114,18 @@ Fonctionnalité: Réouverture d'une habilitation validée
Alors il y a un badge "Validée"


Scénario: Initialisation d'une réouverture bac à sable d'une demande validée en production
Quand j'ai 1 demande d'habilitation "API Impôt Particulier" validée
Et que je vais sur la page tableau de bord
Et que je clique sur "Mettre à jour"
Et que je clique sur "Mettre à jour l'habilitation bac à sable"
Alors je suis sur la page "Demande libre (Bac à sable) - API Impôt Particulier"
Et il y a un message de succès contenant "a bien été réouverte"

Scénario: Initialisation d'une réouverture production d'une demande validée en production
Quand j'ai 1 demande d'habilitation "API Impôt Particulier" validée
Et que je vais sur la page tableau de bord
Et que je clique sur "Mettre à jour"
Et que je clique sur "Mettre à jour l'habilitation de production"
Alors je suis sur la page "Demande libre (Production) - API Impôt Particulier"
Et il y a un message de succès contenant "a bien été réouverte"
22 changes: 22 additions & 0 deletions spec/models/authorization_definition_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,26 @@
it { expect(next_stage_definition.id).to eq('api_impot_particulier') }
end
end

describe '#previous_stage_form' do
subject(:previous_stage_form) { instance.previous_stage_form(authorization_request_class) }

context 'when definition has no stage' do
let(:instance) { described_class.find('api_entreprise') }
let(:authorization_request_class) { AuthorizationRequest::APIEntreprise }

it { is_expected.to be_nil }
end

context 'when definition has stages' do
let(:instance) { described_class.find('api_impot_particulier') }
let(:authorization_request_class) { AuthorizationRequest::APIImpotParticulierSandbox }

it { is_expected.to be_a AuthorizationRequestForm }

it 'selects the previous stage form' do
expect(previous_stage_form.id).to eq('api-impot-particulier-sandbox')
end
end
end
end
33 changes: 33 additions & 0 deletions spec/organizers/reopen_authorization_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,5 +36,38 @@
expect { reopen_authorization_request }.not_to change { authorization_request.reload.state }
end
end

context 'with an authorization_request_class to transition to' do
subject(:reopen_authorization_request) { described_class.call(authorization:, user:, authorization_request_class:) }

let(:authorization_request) { create(:authorization_request, :api_impot_particulier, :validated) }
let(:authorization_request_class) { AuthorizationRequest::APIImpotParticulierSandbox }

it 'transitions the authorization request to a previous stage' do
expect { reopen_authorization_request }.to change { AuthorizationRequest.find(authorization_request.id).class }.from(AuthorizationRequest::APIImpotParticulier).to(AuthorizationRequest::APIImpotParticulierSandbox)
end

it "transistions the authorization request's form to the previous stage's form" do
expect { reopen_authorization_request }.to change { AuthorizationRequest.find(authorization_request.id).form_uid }.from('api-impot-particulier-production').to('api-impot-particulier-sandbox')
end

context 'when the authorization_request_class is from the same stage' do
let(:authorization_request_class) { AuthorizationRequest::APIImpotParticulier }

it "doesn't transitions the authorization_request class" do
expect { reopen_authorization_request }.not_to change { AuthorizationRequest.find(authorization_request.id).class }
end

it "doesn't transitions the authorization_request form" do
expect { reopen_authorization_request }.not_to change { AuthorizationRequest.find(authorization_request.id).form_uid }
end
end

context 'when the authorization_request_class is not an available reopen class' do
let(:authorization_request_class) { AuthorizationRequest::APIHermes }

it { is_expected.to be_failure }
end
end
end
end

0 comments on commit e423b34

Please sign in to comment.