diff --git a/app/assets/images/icons/trash.svg b/app/assets/images/icons/trash.svg new file mode 100644 index 000000000..ea3e1ca31 --- /dev/null +++ b/app/assets/images/icons/trash.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/app/assets/stylesheets/new_design/buttons.scss b/app/assets/stylesheets/new_design/buttons.scss index d2c809c5b..5092221ff 100644 --- a/app/assets/stylesheets/new_design/buttons.scss +++ b/app/assets/stylesheets/new_design/buttons.scss @@ -60,6 +60,10 @@ color: #FFFFFF; border-color: $medium-red; background-color: $medium-red; + + > .icon { + filter: brightness(100); + } } } diff --git a/app/assets/stylesheets/new_design/commencer.scss b/app/assets/stylesheets/new_design/commencer.scss new file mode 100644 index 000000000..5da4faf86 --- /dev/null +++ b/app/assets/stylesheets/new_design/commencer.scss @@ -0,0 +1,11 @@ +@import "constants"; + +.commencer { + .button:first-of-type { + margin-top: 4 * $default-spacer; + } + + .button { + margin-bottom: 2 * $default-spacer; + } +} diff --git a/app/assets/stylesheets/new_design/dossiers_table.scss b/app/assets/stylesheets/new_design/dossiers_table.scss index b3cd92a4e..1f3468039 100644 --- a/app/assets/stylesheets/new_design/dossiers_table.scss +++ b/app/assets/stylesheets/new_design/dossiers_table.scss @@ -70,10 +70,17 @@ width: 110px; } - .follow-col { - width: 200px; + .action-col { text-align: right; padding-left: $default-spacer; padding-right: $default-spacer; } + + .follow-col { + width: 200px; + } + + .delete-col { + width: 150px; + } } diff --git a/app/assets/stylesheets/new_design/forms.scss b/app/assets/stylesheets/new_design/forms.scss index 95beff55e..a5edd446a 100644 --- a/app/assets/stylesheets/new_design/forms.scss +++ b/app/assets/stylesheets/new_design/forms.scss @@ -5,6 +5,10 @@ h1 { text-align: center; margin-bottom: 20px; + + @media (max-width: $two-columns-breakpoint) { + font-size: 28px; + } } hr { diff --git a/app/assets/stylesheets/new_design/icons.scss b/app/assets/stylesheets/new_design/icons.scss index c2efb749a..fd3b8497c 100644 --- a/app/assets/stylesheets/new_design/icons.scss +++ b/app/assets/stylesheets/new_design/icons.scss @@ -105,4 +105,8 @@ &.meh { background-image: image-url("icons/meh-regular.svg"); } + + &.delete { + background-image: image-url("icons/trash.svg"); + } } diff --git a/app/controllers/concerns/procedure_context_concern.rb b/app/controllers/concerns/procedure_context_concern.rb index 307dba95e..d2d7b5a2c 100644 --- a/app/controllers/concerns/procedure_context_concern.rb +++ b/app/controllers/concerns/procedure_context_concern.rb @@ -5,8 +5,8 @@ module ProcedureContextConcern include Devise::StoreLocationExtension def restore_procedure_context - if stored_procedure_id.present? - @procedure = Procedure.publiees.find_by(id: stored_procedure_id) + if has_stored_procedure_path? + @procedure = find_procedure_in_context if @procedure.blank? invalid_procedure_context @@ -16,11 +16,18 @@ module ProcedureContextConcern private - def stored_procedure_id - stored_location = get_stored_location_for(:user) + def has_stored_procedure_path? + get_stored_location_for(:user)&.start_with?('/commencer/') + end - if stored_location.present? && stored_location.include?('procedure_id=') - stored_location.split('procedure_id=').second + def find_procedure_in_context + uri = URI(get_stored_location_for(:user)) + path_components = uri.path.split('/') + + if uri.path.start_with?('/commencer/test/') + Procedure.brouillon.find_by(path: path_components[3]) + elsif uri.path.start_with?('/commencer/') + Procedure.publiee.find_by(path: path_components[2]) else nil end diff --git a/app/controllers/new_user/commencer_controller.rb b/app/controllers/new_user/commencer_controller.rb index b514544d1..325bf3706 100644 --- a/app/controllers/new_user/commencer_controller.rb +++ b/app/controllers/new_user/commencer_controller.rb @@ -1,25 +1,44 @@ module NewUser class CommencerController < ApplicationController - def commencer_test - procedure = Procedure.brouillons.find_by(path: params[:path]) - - if procedure.present? - redirect_to new_dossier_path(procedure_id: procedure.id, brouillon: true) - else - flash.alert = "La démarche est inconnue." - redirect_to root_path - end - end + layout 'procedure_context' def commencer - procedure = Procedure.publiees.find_by(path: params[:path]) + @procedure = Procedure.publiees.find_by(path: params[:path]) - if procedure.present? - redirect_to new_dossier_path(procedure_id: procedure.id) - else + if @procedure.blank? flash.alert = "La démarche est inconnue, ou la création de nouveaux dossiers pour cette démarche est terminée." - redirect_to root_path + return redirect_to root_path end + + render 'commencer/show' + end + + def commencer_test + @procedure = Procedure.brouillons.find_by(path: params[:path]) + + if @procedure.blank? + flash.alert = "La démarche est inconnue, ou cette démarche n’est maintenant plus en test." + return redirect_to root_path + end + + render 'commencer/show' + end + + def sign_in + store_user_location! + redirect_to new_user_session_path + end + + def sign_up + store_user_location! + redirect_to new_user_registration_path + end + + private + + def store_user_location! + procedure = Procedure.find_by(path: params[:path]) + store_location_for(:user, commencer_path(path: procedure.path)) end end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index b1bda2b01..d167a0609 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -85,13 +85,8 @@ module ApplicationHelper tags, type, dossier_id = options.values_at(:tags, :type, :dossier_id) options.except!(:tags, :type, :dossier_id) - if Flipflop.support_form? - params = { tags: tags, type: type, dossier_id: dossier_id }.compact - link_to title, contact_url(params), options - else - mail_to CONTACT_EMAIL, title, - options.merge(subject: "Question à propos de demarches-simplifiees.fr") - end + params = { tags: tags, type: type, dossier_id: dossier_id }.compact + link_to title, contact_url(params), options end def root_path_for_profile(nav_bar_profile) diff --git a/app/helpers/dossier_helper.rb b/app/helpers/dossier_helper.rb index 53c759d5b..812eff956 100644 --- a/app/helpers/dossier_helper.rb +++ b/app/helpers/dossier_helper.rb @@ -23,6 +23,14 @@ module DossierHelper end end + def url_for_new_dossier(procedure) + if procedure.brouillon? + new_dossier_url(procedure_id: procedure.id, brouillon: true) + else + new_dossier_url(procedure_id: procedure.id) + end + end + def dossier_submission_is_closed?(dossier) dossier.brouillon? && dossier.procedure.archivee? end diff --git a/app/helpers/procedure_helper.rb b/app/helpers/procedure_helper.rb index bdedf9416..c6d6db847 100644 --- a/app/helpers/procedure_helper.rb +++ b/app/helpers/procedure_helper.rb @@ -64,7 +64,6 @@ module ProcedureHelper private TOGGLES = { - TypeDeChamp.type_champs.fetch(:siret) => :champ_siret?, TypeDeChamp.type_champs.fetch(:integer_number) => :champ_integer_number?, TypeDeChamp.type_champs.fetch(:repetition) => :champ_repetition? } diff --git a/app/javascript/new_design/administrateur/DraggableItem.js b/app/javascript/new_design/administrateur/DraggableItem.js index f9a55edbb..70dee126f 100644 --- a/app/javascript/new_design/administrateur/DraggableItem.js +++ b/app/javascript/new_design/administrateur/DraggableItem.js @@ -57,7 +57,7 @@ export default { return this.typeChamp === 'header_section'; }, options() { - const options = this.item.options; + const options = this.item.options || {}; for (let key of Object.keys(options)) { options[key] = castBoolean(options[key]); } @@ -77,7 +77,7 @@ export default { libelle: this.item.libelle, mandatory: this.item.mandatory, description: this.item.description, - dropDownList: this.item.drop_down_list.value, + dropDownList: this.item.drop_down_list && this.item.drop_down_list.value, deleted: false, clientId: `id-${clientIds++}` }; diff --git a/app/javascript/new_design/administrateur/champs-editor.js b/app/javascript/new_design/administrateur/champs-editor.js index 6bfb9d43d..4b83af165 100644 --- a/app/javascript/new_design/administrateur/champs-editor.js +++ b/app/javascript/new_design/administrateur/champs-editor.js @@ -10,6 +10,12 @@ Vue.component('DraggableItem', DraggableItem); addEventListener('DOMContentLoaded', () => { const el = document.querySelector('#champs-editor'); + if (el) { + initEditor(el); + } +}); + +function initEditor(el) { const { directUploadsUrl, dragIconUrl } = el.dataset; const state = { @@ -48,7 +54,7 @@ addEventListener('DOMContentLoaded', () => { this.updateAll = updateAll; } }); -}); +} function createUpdateFunctions(app, isAnnotation) { let isSaving = false; diff --git a/app/models/procedure.rb b/app/models/procedure.rb index b79d5ad47..276a90183 100644 --- a/app/models/procedure.rb +++ b/app/models/procedure.rb @@ -184,10 +184,11 @@ class Procedure < ApplicationRecord end def clone(admin, from_library) + is_different_admin = self.administrateur_id != admin.id + populate_champ_stable_ids procedure = self.deep_clone(include: { - types_de_piece_justificative: nil, attestation_template: nil, types_de_champ: :drop_down_list, types_de_champ_private: :drop_down_list @@ -203,6 +204,11 @@ class Procedure < ApplicationRecord [:notice, :deliberation].each { |attachment| clone_attachment(procedure, attachment) } + procedure.types_de_champ += PiecesJustificativesService.types_pj_as_types_de_champ(self) + if is_different_admin || from_library + procedure.types_de_champ.each { |tdc| tdc.options&.delete(:old_pj) } + end + procedure.administrateur = admin procedure.initiated_mail = initiated_mail&.dup procedure.received_mail = received_mail&.dup @@ -215,7 +221,7 @@ class Procedure < ApplicationRecord if from_library procedure.service = nil - elsif self.service.present? && (self.administrateur_id != admin.id) + elsif self.service.present? && is_different_admin procedure.service = self.service.clone_and_assign_to_administrateur(admin) end diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb index 15927cf96..c801a4a56 100644 --- a/app/models/type_de_champ.rb +++ b/app/models/type_de_champ.rb @@ -37,7 +37,7 @@ class TypeDeChamp < ApplicationRecord belongs_to :parent, class_name: 'TypeDeChamp' has_many :types_de_champ, foreign_key: :parent_id, class_name: 'TypeDeChamp', dependent: :destroy - store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles + store_accessor :options, :cadastres, :quartiers_prioritaires, :parcelles_agricoles, :old_pj # TODO simplify after migrating `options` column to (non YAML encoded) JSON class MaybeYaml diff --git a/app/serializers/dossier_serializer.rb b/app/serializers/dossier_serializer.rb index 869aa727c..536c418cf 100644 --- a/app/serializers/dossier_serializer.rb +++ b/app/serializers/dossier_serializer.rb @@ -26,7 +26,7 @@ class DossierSerializer < ActiveModel::Serializer has_many :champs, serializer: ChampSerializer def champs - champs = object.champs.to_a + champs = object.champs.reject { |c| c.type_de_champ.old_pj.present? } if object.expose_legacy_carto_api? champ_carte = champs.find do |champ| @@ -47,6 +47,16 @@ class DossierSerializer < ActiveModel::Serializer [] end + def pieces_justificatives + ActiveModelSerializers::SerializableResource.new(object.pieces_justificatives).serializable_hash + + PiecesJustificativesService.serialize_champs_as_pjs(object) + end + + def types_de_piece_justificative + ActiveModelSerializers::SerializableResource.new(object.types_de_piece_justificative).serializable_hash + + PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object) + end + def email object.user&.email end diff --git a/app/serializers/procedure_serializer.rb b/app/serializers/procedure_serializer.rb index 674d8ab91..3d259bfc8 100644 --- a/app/serializers/procedure_serializer.rb +++ b/app/serializers/procedure_serializer.rb @@ -16,7 +16,7 @@ class ProcedureSerializer < ActiveModel::Serializer has_one :geographic_information, serializer: ModuleApiCartoSerializer has_many :types_de_champ, serializer: TypeDeChampSerializer has_many :types_de_champ_private, serializer: TypeDeChampSerializer - has_many :types_de_piece_justificative, serializer: TypeDePieceJustificativeSerializer + has_many :types_de_piece_justificative def archived_at object.archived_at&.in_time_zone('UTC') @@ -43,4 +43,13 @@ class ProcedureSerializer < ActiveModel::Serializer ModuleAPICarto.new(procedure: object) end end + + def types_de_champ + object.types_de_champ.reject { |c| c.old_pj.present? } + end + + def types_de_piece_justificative + ActiveModelSerializers::SerializableResource.new(object.types_de_piece_justificative).serializable_hash + + PiecesJustificativesService.serialize_types_de_champ_as_type_pj(object) + end end diff --git a/app/services/pieces_justificatives_service.rb b/app/services/pieces_justificatives_service.rb index 6a68a0d7b..dd617b28b 100644 --- a/app/services/pieces_justificatives_service.rb +++ b/app/services/pieces_justificatives_service.rb @@ -31,4 +31,68 @@ class PiecesJustificativesService missing_pjs.map { |pj| "La pièce jointe #{pj.libelle.truncate(200)} doit être fournie." } end + + def self.types_pj_as_types_de_champ(procedure) + order_place = procedure.types_de_champ.last&.order_place || 0 + types_de_champ = [ + TypeDeChamp.new( + libelle: "Pièces jointes", + type_champ: TypeDeChamp.type_champs.fetch(:header_section), + order_place: order_place + ) + ] + types_de_champ += procedure.types_de_piece_justificative.map do |tpj| + order_place += 1 + description = tpj.description + if tpj.lien_demarche.present? + if description.present? + description += "\n" + end + description += "Récupérer le formulaire vierge pour mon dossier : #{tpj.lien_demarche}" + end + TypeDeChamp.new( + libelle: tpj.libelle, + type_champ: TypeDeChamp.type_champs.fetch(:piece_justificative), + description: description, + order_place: order_place, + mandatory: tpj.mandatory, + old_pj: { + stable_id: tpj.id + } + ) + end + if types_de_champ.count > 1 + types_de_champ + else + [] + end + end + + def self.serialize_types_de_champ_as_type_pj(procedure) + tdcs = procedure.types_de_champ.select { |type_champ| type_champ.old_pj.present? } + tdcs.map.with_index do |type_champ, order_place| + description = type_champ.description + if /^(?.*?)(?:[\r\n]+)Récupérer le formulaire vierge pour mon dossier : (?http.*)$/m =~ description + description = original_description + end + { + id: type_champ.old_pj[:stable_id], + libelle: type_champ.libelle, + description: description, + order_place: order_place, + lien_demarche: lien_demarche + } + end + end + + def self.serialize_champs_as_pjs(dossier) + dossier.champs.select { |champ| champ.type_de_champ.old_pj }.map do |champ| + { + created_at: champ.created_at&.in_time_zone('UTC'), + type_de_piece_justificative_id: champ.type_de_champ.old_pj[:stable_id], + content_url: champ.for_api, + user: champ.dossier.user + } + end + end end diff --git a/app/services/types_de_champ_service.rb b/app/services/types_de_champ_service.rb index 288e30f59..411898f93 100644 --- a/app/services/types_de_champ_service.rb +++ b/app/services/types_de_champ_service.rb @@ -2,7 +2,6 @@ class TypesDeChampService include Rails.application.routes.url_helpers TOGGLES = { - TypeDeChamp.type_champs.fetch(:siret) => :champ_siret?, TypeDeChamp.type_champs.fetch(:integer_number) => :champ_integer_number?, TypeDeChamp.type_champs.fetch(:repetition) => :champ_repetition? } diff --git a/app/views/admin/attestation_templates/edit.html.haml b/app/views/admin/attestation_templates/edit.html.haml index 5dbc5b309..34b4572fe 100644 --- a/app/views/admin/attestation_templates/edit.html.haml +++ b/app/views/admin/attestation_templates/edit.html.haml @@ -66,6 +66,12 @@ = f.label :footer, 'Pied de page' = f.text_field :footer, class: 'form-control', maxlength: 190 + - if @attestation_template.activated && @procedure.locked? + .row + .col-md-12 + .pull-right + %p.help-block L’attestation ne peut plus être désactivée car la démarche a déjà été publiée. + %button.btn.btn-primary{ formaction: admin_procedure_attestation_template_preview_path, formtarget: '_blank' } Prévisualiser .pull-right diff --git a/app/views/commencer/show.html.haml b/app/views/commencer/show.html.haml new file mode 100644 index 000000000..5e71bbd19 --- /dev/null +++ b/app/views/commencer/show.html.haml @@ -0,0 +1,30 @@ +- content_for(:title, @procedure.libelle) + +.commencer.form + - if !user_signed_in? + %h1 Commencer la démarche + = link_to 'Créer un compte demarches-simplifiees.fr', commencer_sign_up_path(path: @procedure.path), class: ['button large expand primary'] + = link_to 'J’ai déjà un compte', commencer_sign_in_path(path: @procedure.path), class: ['button large expand'] + + - else + - dossiers = current_user.dossiers.where(procedure: @procedure) + - drafts = dossiers.merge(Dossier.state_brouillon) + - not_drafts = dossiers.merge(Dossier.state_not_brouillon) + + - if dossiers.count == 0 + = link_to 'Commencer la démarche', url_for_new_dossier(@procedure), class: ['button large expand primary'] + + - elsif drafts.count == 1 && not_drafts.count == 0 + %h1 Vous avez déjà commencé à remplir un dossier + = link_to 'Continuer à remplir mon dossier', brouillon_dossier_path(drafts.first), class: ['button large expand primary'] + = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand'] + + - elsif not_drafts.count == 1 + %h1 Vous avez déjà déposé un dossier + = link_to 'Voir mon dossier', dossier_path(not_drafts.first), class: ['button large expand primary'] + = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand'] + + - else + %h1 Vous avez déjà des dossiers pour cette démarche + = link_to 'Voir mes dossiers en cours', dossiers_path, class: ['button large expand primary'] + = link_to 'Commencer un nouveau dossier', url_for_new_dossier(@procedure), class: ['button large expand'] diff --git a/app/views/demandes/new.html.haml b/app/views/demandes/new.html.haml index 40de202b1..14f0e3789 100644 --- a/app/views/demandes/new.html.haml +++ b/app/views/demandes/new.html.haml @@ -44,7 +44,7 @@ = text_field_tag :phone, nil, required: true = label_tag :source do - Comment avez-vous entendu parlé de demarches-simplifiees.fr ? + Comment avez-vous entendu parler de demarches-simplifiees.fr ? %span.mandatory * = text_field_tag :source, nil, required: true diff --git a/app/views/new_gestionnaire/procedures/show.html.haml b/app/views/new_gestionnaire/procedures/show.html.haml index ca1a06a13..11f17fc4f 100644 --- a/app/views/new_gestionnaire/procedures/show.html.haml +++ b/app/views/new_gestionnaire/procedures/show.html.haml @@ -77,7 +77,7 @@ = render partial: "header_field", locals: { field: { "label" => "Statut", "table" => "self", "column" => "state" }, classname: "status-col" } - %th.follow-col + %th.action-col.follow-col %span.dropdown %button.button.dropdown-button Personnaliser @@ -112,7 +112,7 @@ %td.status-col = link_to(gestionnaire_dossier_path(@procedure, dossier), class: 'cell-link') do = render partial: 'shared/dossiers/status_badge', locals: { dossier: dossier } - %td.follow-col= render partial: 'dossier_actions', locals: { procedure: @procedure, dossier: dossier, dossier_is_followed: @followed_dossiers_id.include?(dossier.id) } + %td.action-col.follow-col= render partial: 'dossier_actions', locals: { procedure: @procedure, dossier: dossier, dossier_is_followed: @followed_dossiers_id.include?(dossier.id) } = paginate @dossiers - else %h2.empty-text Aucun dossier diff --git a/app/views/new_gestionnaire/recherche/index.html.haml b/app/views/new_gestionnaire/recherche/index.html.haml index 68e93156a..3af866a83 100644 --- a/app/views/new_gestionnaire/recherche/index.html.haml +++ b/app/views/new_gestionnaire/recherche/index.html.haml @@ -14,7 +14,7 @@ %th Démarche %th Demandeur %th.status-col Statut - %th.follow-col + %th.action-col.follow-col %tbody - @dossiers.each do |dossier| / # FIXME: here we have a n+1, we fire a request @@ -31,6 +31,6 @@ %td.status-col = link_to(dossier_linked_path(current_gestionnaire, dossier), class: 'cell-link') do = render partial: 'shared/dossiers/status_badge', locals: { dossier: dossier } - %td.follow-col= render partial: 'new_gestionnaire/procedures/dossier_actions', locals: { procedure: dossier.procedure, dossier: dossier, dossier_is_followed: @followed_dossiers_id.include?(dossier.id) } + %td.action-col.follow-col= render partial: 'new_gestionnaire/procedures/dossier_actions', locals: { procedure: dossier.procedure, dossier: dossier, dossier_is_followed: @followed_dossiers_id.include?(dossier.id) } - else %h2 Aucun dossier correspondant à votre recherche n'a été trouvé diff --git a/app/views/new_user/dossiers/index.html.haml b/app/views/new_user/dossiers/index.html.haml index 80f6a9aff..347961d81 100644 --- a/app/views/new_user/dossiers/index.html.haml +++ b/app/views/new_user/dossiers/index.html.haml @@ -31,6 +31,7 @@ %th Démarche %th.status-col Statut %th.updated-at-col Mis à jour + %th %tbody - @dossiers.each do |dossier| %tr @@ -49,6 +50,11 @@ %td.updated-at-col = link_to(url_for_dossier(dossier), class: 'cell-link') do = dossier.updated_at.strftime("%d/%m/%Y") + %td.action-col.delete-col + - if dossier.brouillon? + = link_to(ask_deletion_dossier_path(dossier), method: :post, class: 'button danger', data: { disable: true, confirm: "En continuant, vous allez supprimer ce dossier ainsi que les informations qu’il contient. Toute suppression entraine l’annulation de la démarche en cours.\n\nConfirmer la suppression ?" }) do + %span.icon.delete + Supprimer = paginate(@dossiers) - if current_user.feedbacks.empty? || current_user.feedbacks.last.created_at < 1.month.ago diff --git a/config/features.rb b/config/features.rb index 6be7eecb5..2faf85f48 100644 --- a/config/features.rb +++ b/config/features.rb @@ -7,8 +7,6 @@ Flipflop.configure do strategy :default group :champs do - feature :champ_siret, - title: "Champ SIRET" feature :champ_integer_number, title: "Champ nombre entier" feature :champ_repetition, @@ -17,7 +15,6 @@ Flipflop.configure do feature :web_hook feature :publish_draft - feature :support_form feature :enable_email_login_token feature :new_champs_editor diff --git a/config/routes.rb b/config/routes.rb index 5ad479ced..57ce1673c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -265,6 +265,8 @@ Rails.application.routes.draw do namespace :commencer do get '/test/:path', action: 'commencer_test', as: :test get '/:path', action: 'commencer' + get '/:path/sign_in', action: 'sign_in', as: :sign_in + get '/:path/sign_up', action: 'sign_up', as: :sign_up end resources :dossiers, only: [:index, :show, :new] do diff --git a/lib/tasks/2019_01_16_fix_automatic_dossier_logs.rake b/lib/tasks/2019_01_16_fix_automatic_dossier_logs.rake new file mode 100644 index 000000000..e4039fa77 --- /dev/null +++ b/lib/tasks/2019_01_16_fix_automatic_dossier_logs.rake @@ -0,0 +1,61 @@ +class FixAutomaticDossierLogs_2019_01_16 + def find_handlers + # rubocop:disable Security/YAMLLoad + Delayed::Job.where(queue: 'cron') + .map { |job| YAML.load(job.handler) } + .select { |handler| handler.job_data['job_class'] == 'AutoReceiveDossiersForProcedureJob' } + # rubocop:enable Security/YAMLLoad + end + + def run + handlers = find_handlers + + handlers + .map { |handler| handler.job_data['arguments'] } + .each do |(procedure_id, state)| + + procedure = Procedure + .includes(:administrateur, dossiers: [:dossier_operation_logs, :follows]) + .find(procedure_id) + + rake_puts "working on procedure #{procedure_id}, #{procedure.libelle} whose admin is #{procedure.administrateur.email}" + + case state + when Dossier.states.fetch(:en_instruction) + dossiers = procedure.dossiers.state_en_instruction + operation = 'passer_en_instruction' + when Dossier.states.fetch(:accepte) + dossiers = procedure.dossiers.accepte + operation = 'accepter' + end + + dossier_operation_logs = DossierOperationLog + .where(dossier: dossiers, operation: operation) + + rake_puts "affecting #{dossier_operation_logs.count} dossier_operation_logs" + + dossier_operation_logs + .update_all(gestionnaire_id: nil, automatic_operation: true) + + # if the dossier is only followed by the procedure administrateur + # unfollow + if state == Dossier.states.fetch(:en_instruction) + dossier_to_unfollows = dossiers + .select { |d| d.follows.count == 1 && d.follows.first.gestionnaire.email == procedure.administrateur.email } + + rake_puts "affecting #{dossier_to_unfollows.count} dossiers" + + dossier_to_unfollows + .each { |d| d.follows.destroy_all } + end + + rake_puts "" + end + end +end + +namespace :'2019_01_16_fix_automatic_dossier_logs' do + task run: :environment do + FixAutomaticDossierLogs_2019_01_16.new.run + end +end diff --git a/spec/controllers/concerns/procedure_context_concern_spec.rb b/spec/controllers/concerns/procedure_context_concern_spec.rb index 42e616305..5911e1686 100644 --- a/spec/controllers/concerns/procedure_context_concern_spec.rb +++ b/spec/controllers/concerns/procedure_context_concern_spec.rb @@ -24,7 +24,7 @@ RSpec.describe ProcedureContextConcern, type: :controller do end end - context 'when no procedure_id is present in the stored return location' do + context 'when the stored return location is not a procedure URL' do before do controller.store_location_for(:user, dossiers_path) end @@ -36,9 +36,9 @@ RSpec.describe ProcedureContextConcern, type: :controller do end context 'when a procedure location has been stored' do - context 'when the stored procedure does not exist' do + context 'when the procedure path does not exist' do before do - controller.store_location_for(:user, new_dossier_path(procedure_id: '0')) + controller.store_location_for(:user, commencer_path(path: 'non-existent-path')) end it 'redirects with an error' do @@ -47,11 +47,11 @@ RSpec.describe ProcedureContextConcern, type: :controller do end end - context 'when the stored procedure is not published' do - let(:procedure) { create :procedure } + context 'when the procedure path exists, but not with the same publication status' do + let(:published_procedure) { create :procedure, :published } before do - controller.store_location_for(:user, new_dossier_path(procedure_id: procedure.id)) + controller.store_location_for(:user, commencer_test_path(path: published_procedure.path)) end it 'redirects with an error' do @@ -60,16 +60,29 @@ RSpec.describe ProcedureContextConcern, type: :controller do end end - context 'when the stored procedure exists' do - let(:procedure) { create :procedure, :published } + context 'when the stored procedure is in test' do + let(:test_procedure) { create :procedure, :with_path } before do - controller.store_location_for(:user, new_dossier_path(procedure_id: procedure.id)) + controller.store_location_for(:user, commencer_test_path(path: test_procedure.path)) end it 'succeeds, and assigns the procedure on the controller' do expect(subject.status).to eq 200 - expect(assigns(:procedure)).to eq procedure + expect(assigns(:procedure)).to eq test_procedure + end + end + + context 'when the stored procedure is published' do + let(:published_procedure) { create :procedure, :published } + + before do + controller.store_location_for(:user, commencer_path(path: published_procedure.path)) + end + + it 'succeeds, and assigns the procedure on the controller' do + expect(subject.status).to eq 200 + expect(assigns(:procedure)).to eq published_procedure end end end diff --git a/spec/controllers/new_user/commencer_controller_spec.rb b/spec/controllers/new_user/commencer_controller_spec.rb index 3bede7f9b..7fbaea275 100644 --- a/spec/controllers/new_user/commencer_controller_spec.rb +++ b/spec/controllers/new_user/commencer_controller_spec.rb @@ -2,39 +2,88 @@ require 'spec_helper' describe NewUser::CommencerController, type: :controller do let(:user) { create(:user) } - let(:procedure) { create(:procedure, :published) } - let(:procedure_id) { procedure.id } + let(:published_procedure) { create(:procedure, :published) } + let(:draft_procedure) { create(:procedure, :with_path) } - describe 'GET #commencer' do + describe '#commencer' do subject { get :commencer, params: { path: path } } - let(:path) { procedure.path } - it { expect(subject.status).to eq 302 } - it { expect(subject).to redirect_to new_dossier_path(procedure_id: procedure.id) } + context 'when the path is for a published procedure' do + let(:path) { published_procedure.path } - context 'when procedure path does not exist' do + it 'renders the view' do + expect(subject.status).to eq(200) + expect(subject).to render_template('show') + expect(assigns(:procedure)).to eq published_procedure + end + end + + context 'when the path is for a non-published procedure' do + let(:path) { draft_procedure.path } + + it 'redirects with an error message' do + expect(subject).to redirect_to(root_path) + end + end + + context 'when the path does not exist' do let(:path) { 'hello' } - it { expect(subject).to redirect_to(root_path) } + it 'redirects with an error message' do + expect(subject).to redirect_to(root_path) + end end end - describe 'GET #commencer_test' do - before do - Flipflop::FeatureSet.current.test!.switch!(:publish_draft, true) + describe '#commencer_test' do + subject { get :commencer_test, params: { path: path } } + + context 'when the path is for a draft procedure' do + let(:path) { draft_procedure.path } + + it 'renders the view' do + expect(subject.status).to eq(200) + expect(subject).to render_template('show') + expect(assigns(:procedure)).to eq draft_procedure + end end - subject { get :commencer_test, params: { path: path } } - let(:procedure) { create(:procedure, :with_path) } - let(:path) { procedure.path } + context 'when the path is for a published procedure' do + let(:path) { published_procedure.path } - it { expect(subject.status).to eq 302 } - it { expect(subject).to redirect_to new_dossier_path(procedure_id: procedure.id, brouillon: true) } + it 'redirects with an error message' do + expect(subject).to redirect_to(root_path) + end + end - context 'when procedure path does not exist' do + context 'when the path does not exist' do let(:path) { 'hello' } - it { expect(subject).to redirect_to(root_path) } + it 'redirects with an error message' do + expect(subject).to redirect_to(root_path) + end end end + + describe '#sign_in' do + subject { get :sign_in, params: { path: published_procedure.path } } + + it 'set the path to return after sign-in to the dossier creation path' do + subject + expect(controller.stored_location_for(:user)).to eq(commencer_path(path: published_procedure.path)) + end + + it { expect(subject).to redirect_to(new_user_session_path) } + end + + describe '#sign_up' do + subject { get :sign_up, params: { path: published_procedure.path } } + + it 'set the path to return after sign-up to the dossier creation path' do + subject + expect(controller.stored_location_for(:user)).to eq(commencer_path(path: published_procedure.path)) + end + + it { expect(subject).to redirect_to(new_user_registration_path) } + end end diff --git a/spec/controllers/users/registrations_controller_spec.rb b/spec/controllers/users/registrations_controller_spec.rb index f1d8e036c..c5cbd2155 100644 --- a/spec/controllers/users/registrations_controller_spec.rb +++ b/spec/controllers/users/registrations_controller_spec.rb @@ -27,7 +27,7 @@ describe Users::RegistrationsController, type: :controller do let(:procedure) { create :procedure, :published } before do - controller.store_location_for(:user, new_dossier_path(procedure_id: procedure.id)) + controller.store_location_for(:user, commencer_path(path: procedure.path)) end it 'makes the saved procedure available' do diff --git a/spec/controllers/users/sessions_controller_spec.rb b/spec/controllers/users/sessions_controller_spec.rb index e12521849..efa388790 100644 --- a/spec/controllers/users/sessions_controller_spec.rb +++ b/spec/controllers/users/sessions_controller_spec.rb @@ -179,7 +179,7 @@ describe Users::SessionsController, type: :controller do let(:procedure) { create :procedure, :published } before do - controller.store_location_for(:user, new_dossier_path(procedure_id: procedure.id)) + controller.store_location_for(:user, commencer_path(path: procedure.path)) end it 'makes the saved procedure available' do diff --git a/spec/features/new_gestionnaire/gestionnaire_spec.rb b/spec/features/new_gestionnaire/gestionnaire_spec.rb index dd0aab750..d81906dc2 100644 --- a/spec/features/new_gestionnaire/gestionnaire_spec.rb +++ b/spec/features/new_gestionnaire/gestionnaire_spec.rb @@ -14,10 +14,16 @@ feature 'The gestionnaire part' do scenario 'a gestionnaire can fill a dossier' do visit commencer_path(path: procedure.path) + click_on 'J’ai déjà un compte' expect(page).to have_current_path new_user_session_path sign_in_with(gestionnaire.email, password, true) + expect(page).to have_current_path(commencer_path(path: procedure.path)) + click_on 'Commencer la démarche' + + expect(page).to have_content('Identifier votre établissement') + expect(page).to have_current_path(siret_dossier_path(procedure.reload.dossiers.last)) expect(page).to have_content(procedure.libelle) end end diff --git a/spec/features/new_user/brouillon_spec.rb b/spec/features/new_user/brouillon_spec.rb index 748572433..4cc1142e2 100644 --- a/spec/features/new_user/brouillon_spec.rb +++ b/spec/features/new_user/brouillon_spec.rb @@ -130,11 +130,15 @@ feature 'The user' do def log_in(email, password, procedure) visit "/commencer/#{procedure.path}" - expect(page).to have_current_path(new_user_session_path) + click_on 'J’ai déjà un compte' - fill_in 'user_email', with: email - fill_in 'user_password', with: password - click_on 'Se connecter' + expect(page).to have_current_path(new_user_session_path) + sign_in_with(email, password) + + expect(page).to have_current_path("/commencer/#{procedure.path}") + click_on 'Commencer la démarche' + + expect(page).to have_content("Données d'identité") expect(page).to have_current_path(identite_dossier_path(user_dossier)) end diff --git a/spec/features/new_user/dossier_creation_spec.rb b/spec/features/new_user/dossier_creation_spec.rb index a45af4ba0..0944d7462 100644 --- a/spec/features/new_user/dossier_creation_spec.rb +++ b/spec/features/new_user/dossier_creation_spec.rb @@ -17,10 +17,10 @@ feature 'Creating a new dossier:' do before do visit commencer_path(path: procedure.path) + click_on 'Commencer la démarche' - expect(page).to have_content(procedure.libelle) - expect(page).to have_content(procedure.description) - expect(page).to have_content(procedure.service.email) + expect(page).to have_current_path identite_dossier_path(user.reload.dossiers.last) + expect_page_to_have_procedure_description(procedure) fill_in 'individual_nom', with: 'Nom' fill_in 'individual_prenom', with: 'Prenom' @@ -77,13 +77,12 @@ feature 'Creating a new dossier:' do .to_return(status: 404, body: '') end - scenario 'the user can enter the SIRET of its etablissement and create a new draft', vcr: { cassette_name: 'api_adresse_search_paris_3' }, js: true do + scenario 'the user can enter the SIRET of its etablissement and create a new draft', vcr: { cassette_name: 'api_adresse_search_paris_3' } do visit commencer_path(path: procedure.path) + click_on 'Commencer la démarche' - expect(page).to have_current_path(siret_dossier_path(dossier)) - expect(page).to have_content(procedure.libelle) - expect(page).to have_content(procedure.description) - expect(page).to have_content(procedure.service.email) + expect(page).to have_current_path siret_dossier_path(dossier) + expect_page_to_have_procedure_description(procedure) fill_in 'Numéro SIRET', with: siret click_on 'Valider' @@ -97,7 +96,10 @@ feature 'Creating a new dossier:' do scenario 'the user is notified when its SIRET is invalid' do visit commencer_path(path: procedure.path) + click_on 'Commencer la démarche' + expect(page).to have_current_path(siret_dossier_path(dossier)) + expect_page_to_have_procedure_description(procedure) fill_in 'Numéro SIRET', with: '0000' click_on 'Valider' diff --git a/spec/features/new_user/linked_dropdown_spec.rb b/spec/features/new_user/linked_dropdown_spec.rb index a175f407a..769057fcd 100644 --- a/spec/features/new_user/linked_dropdown_spec.rb +++ b/spec/features/new_user/linked_dropdown_spec.rb @@ -48,11 +48,16 @@ feature 'linked dropdown lists' do def log_in(email, password, procedure) visit "/commencer/#{procedure.path}" + click_on 'J’ai déjà un compte' + expect(page).to have_current_path(new_user_session_path) - fill_in 'user_email', with: email - fill_in 'user_password', with: password - click_on 'Se connecter' + sign_in_with(email, password) + + expect(page).to have_current_path(commencer_path(path: procedure.path)) + click_on 'Commencer la démarche' + + expect(page).to have_content("Données d'identité") expect(page).to have_current_path(identite_dossier_path(user_dossier)) end diff --git a/spec/features/new_user/list_dossiers_spec.rb b/spec/features/new_user/list_dossiers_spec.rb index 999aef5d6..3e36e97d8 100644 --- a/spec/features/new_user/list_dossiers_spec.rb +++ b/spec/features/new_user/list_dossiers_spec.rb @@ -5,6 +5,7 @@ describe 'user access to the list of his dossier' do let!(:last_updated_dossier) { create(:dossier, :with_entreprise, user: user, state: Dossier.states.fetch(:en_construction)) } let!(:dossier1) { create(:dossier, :with_entreprise, user: user, state: Dossier.states.fetch(:en_construction)) } let!(:dossier2) { create(:dossier, :with_entreprise) } + let!(:dossier_brouillon) { create(:dossier, :with_entreprise, user: user) } let!(:dossier_archived) { create(:dossier, :with_entreprise, user: user, state: Dossier.states.fetch(:en_construction)) } let(:dossiers_per_page) { 25 } @@ -43,6 +44,21 @@ describe 'user access to the list of his dossier' do expect(page).to have_content(dossier_archived.procedure.libelle) end + it 'should have link to only delete brouillon' do + expect(page).to have_link(nil, href: ask_deletion_dossier_path(dossier_brouillon)) + expect(page).not_to have_link(nil, href: ask_deletion_dossier_path(dossier1)) + end + + context 'when user clicks on delete brouillon list', js: true do + before do + find(:xpath, "//a[@href='#{ask_deletion_dossier_path(dossier_brouillon)}']").click + page.driver.browser.switch_to.alert.accept + end + scenario 'dossier is deleted' do + expect(page).not_to have_link("Supprimer", href: dossier_brouillon.procedure.libelle) + end + end + context 'when user clicks on a projet in list', js: true do before do page.click_on(dossier1.procedure.libelle) diff --git a/spec/features/new_user/sign_up_spec.rb b/spec/features/new_user/sign_up_spec.rb index 17063020d..516a9fb4f 100644 --- a/spec/features/new_user/sign_up_spec.rb +++ b/spec/features/new_user/sign_up_spec.rb @@ -41,15 +41,20 @@ feature 'Signing up:' do end scenario 'a new user can sign-up and fill the procedure' do - expect(page).to have_current_path new_user_session_path click_on 'Créer un compte' + expect(page).to have_current_path new_user_registration_path expect_page_to_have_procedure_description(procedure) sign_up_with user_email, user_password expect(page).to have_content "nous avons besoin de vérifier votre adresse #{user_email}" click_confirmation_link_for user_email + + expect(page).to have_current_path(commencer_path(path: procedure.path)) expect(page).to have_content 'Votre compte a été activé' + click_on 'Commencer la démarche' + + expect(page).to have_current_path identite_dossier_path(procedure.reload.dossiers.last) expect_page_to_have_procedure_description(procedure) end end diff --git a/spec/features/sessions/sign_in_spec.rb b/spec/features/sessions/sign_in_spec.rb index 378d41dcb..3dc40531b 100644 --- a/spec/features/sessions/sign_in_spec.rb +++ b/spec/features/sessions/sign_in_spec.rb @@ -21,11 +21,15 @@ feature 'Signin in:' do end scenario 'an existing user can sign-in and fill the procedure' do + click_on 'J’ai déjà un compte' expect(page).to have_current_path new_user_session_path expect_page_to_have_procedure_description(procedure) sign_in_with user.email, password + expect(page).to have_current_path(commencer_path(path: procedure.path)) + click_on 'Commencer la démarche' + expect(page).to have_current_path identite_dossier_path(user.reload.dossiers.last) expect_page_to_have_procedure_description(procedure) expect(page).to have_content "Données d'identité" diff --git a/spec/lib/tasks/2019_01_16_fix_automatic_dossier_logs_spec.rb b/spec/lib/tasks/2019_01_16_fix_automatic_dossier_logs_spec.rb new file mode 100644 index 000000000..b41bafe81 --- /dev/null +++ b/spec/lib/tasks/2019_01_16_fix_automatic_dossier_logs_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +load Rails.root.join('lib', 'tasks', '2019_01_16_fix_automatic_dossier_logs.rake') + +describe '2019_01_16_fix_automatic_dossier_logs' do + let!(:rake_task) { Rake::Task['2019_01_16_fix_automatic_dossier_logs:run'] } + let!(:administrateur) { create(:administrateur) } + let!(:another_gestionnaire) { create(:gestionnaire) } + let!(:procedure) { create(:procedure, administrateur: administrateur) } + let!(:dossier) { create(:dossier, procedure: procedure) } + let!(:fix_automatic_dossier_logs) { FixAutomaticDossierLogs_2019_01_16.new } + + before do + allow(fix_automatic_dossier_logs).to receive(:find_handlers) + .and_return([double(job_data: { 'arguments' => [procedure.id, final_state] })]) + end + + subject do + fix_automatic_dossier_logs.run + dossier.reload + end + + context 'when the dossiers are automatically moved to en_instruction' do + let(:final_state) { 'en_instruction' } + + context 'and a dossier has been accidentally affected to an administrateur' do + before do + dossier.passer_en_instruction!(administrateur.gestionnaire) + + control = DossierOperationLog.create( + gestionnaire: another_gestionnaire, + operation: 'refuser', + automatic_operation: false + ) + + dossier.dossier_operation_logs << control + subject + end + + it { expect(dossier.follows.count).to eq(0) } + + it do + expect(dossier_logs).to match_array([ + [nil, 'passer_en_instruction', true], + [another_gestionnaire.id, "refuser", false] + ]) + end + end + + context ', followed anyway by another person and accidentally ...' do + before do + another_gestionnaire.follow(dossier) + dossier.passer_en_instruction!(administrateur.gestionnaire) + + subject + end + + it { expect(dossier.follows.count).to eq(2) } + it { expect(dossier_logs).to match([[nil, 'passer_en_instruction', true]]) } + end + end + + context 'when the dossiers are automatically moved to accepte' do + let(:final_state) { 'accepte' } + + context 'and a dossier has been accidentally affected to an administrateur' do + before do + dossier.accepter!(administrateur.gestionnaire, '') + + subject + end + + it { expect(dossier_logs).to match([[nil, 'accepter', true]]) } + end + end + + private + + def dossier_logs + dossier.dossier_operation_logs.pluck(:gestionnaire_id, :operation, :automatic_operation) + end +end diff --git a/spec/models/procedure_spec.rb b/spec/models/procedure_spec.rb index 1e8d964cb..f69fffc46 100644 --- a/spec/models/procedure_spec.rb +++ b/spec/models/procedure_spec.rb @@ -336,6 +336,7 @@ describe Procedure do let!(:type_de_champ_0) { create(:type_de_champ, procedure: procedure, order_place: 0) } let!(:type_de_champ_1) { create(:type_de_champ, procedure: procedure, order_place: 1) } let!(:type_de_champ_2) { create(:type_de_champ_drop_down_list, procedure: procedure, order_place: 2) } + let!(:type_de_champ_pj) { create(:type_de_champ_piece_justificative, procedure: procedure, order_place: 3, old_pj: { stable_id: 2713 }) } let!(:type_de_champ_private_0) { create(:type_de_champ, :private, procedure: procedure, order_place: 0) } let!(:type_de_champ_private_1) { create(:type_de_champ, :private, procedure: procedure, order_place: 1) } let!(:type_de_champ_private_2) { create(:type_de_champ_drop_down_list, :private, procedure: procedure, order_place: 2) } @@ -366,13 +367,12 @@ describe Procedure do it 'should duplicate specific objects with different id' do expect(subject.id).not_to eq(procedure.id) - expect(subject.types_de_piece_justificative.size).to eq procedure.types_de_piece_justificative.size - expect(subject.types_de_champ.size).to eq procedure.types_de_champ.size + expect(subject.types_de_champ.size).to eq(procedure.types_de_champ.size + 1 + procedure.types_de_piece_justificative.size) expect(subject.types_de_champ_private.size).to eq procedure.types_de_champ_private.size expect(subject.types_de_champ.map(&:drop_down_list).compact.size).to eq procedure.types_de_champ.map(&:drop_down_list).compact.size expect(subject.types_de_champ_private.map(&:drop_down_list).compact.size).to eq procedure.types_de_champ_private.map(&:drop_down_list).compact.size - subject.types_de_champ.zip(procedure.types_de_champ).each do |stc, ptc| + procedure.types_de_champ.zip(subject.types_de_champ).each do |ptc, stc| expect(stc).to have_same_attributes_as(ptc) end @@ -380,10 +380,6 @@ describe Procedure do expect(stc).to have_same_attributes_as(ptc) end - subject.types_de_piece_justificative.zip(procedure.types_de_piece_justificative).each do |stc, ptc| - expect(stc).to have_same_attributes_as(ptc) - end - expect(subject.attestation_template.title).to eq(procedure.attestation_template.title) expect(subject.cloned_from_library).to be(false) @@ -393,7 +389,19 @@ describe Procedure do expect(cloned_procedure).to have_same_attributes_as(procedure) end - context 'when the procedure is clone from the library' do + it 'should not clone piece justificatives but create corresponding champs' do + expect(subject.types_de_piece_justificative.size).to eq(0) + + champs_pj = subject.types_de_champ[procedure.types_de_champ.size + 1, procedure.types_de_piece_justificative.size] + champs_pj.zip(procedure.types_de_piece_justificative).each do |stc, ptpj| + expect(stc.libelle).to eq(ptpj.libelle) + expect(stc.description).to eq(ptpj.description) + expect(stc.mandatory).to eq(ptpj.mandatory) + expect(stc.old_pj[:stable_id]).to eq(ptpj.id) + end + end + + context 'when the procedure is cloned from the library' do let(:from_library) { true } it { expect(subject.cloned_from_library).to be(true) } @@ -401,6 +409,12 @@ describe Procedure do it 'should set service_id to nil' do expect(subject.service).to eq(nil) end + + it 'should discard old pj information' do + subject.types_de_champ.each do |stc| + expect(stc.old_pj).to be_nil + end + end end it 'should keep service_id' do @@ -415,6 +429,12 @@ describe Procedure do expect(subject.service.administrateur_id).not_to eq(service.administrateur_id) expect(subject.service.attributes.except("id", "administrateur_id", "created_at", "updated_at")).to eq(service.attributes.except("id", "administrateur_id", "created_at", "updated_at")) end + + it 'should discard old pj information' do + subject.types_de_champ.each do |stc| + expect(stc.old_pj).to be_nil + end + end end it 'should duplicate existing mail_templates' do diff --git a/spec/serializers/dossier_serializer_spec.rb b/spec/serializers/dossier_serializer_spec.rb index aa9e51a28..681baeab7 100644 --- a/spec/serializers/dossier_serializer_spec.rb +++ b/spec/serializers/dossier_serializer_spec.rb @@ -45,4 +45,60 @@ describe DossierSerializer do } end end + + context 'when a type PJ was cloned to a type champ PJ' do + let(:original_procedure) do + p = create(:procedure, :published) + p.types_de_piece_justificative.create( + libelle: "Vidéo de votre demande de subvention", + description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique", + lien_demarche: "https://www.dance-academy.gouv.fr", + order_place: 0 + ) + p + end + + let(:procedure) do + p = original_procedure.clone(original_procedure.administrateur, false) + p.save + p + end + + let(:type_pj) { original_procedure.types_de_piece_justificative.first } + let(:migrated_type_champ) { procedure.types_de_champ.find_by(libelle: type_pj.libelle) } + let(:dossier) { create(:dossier, procedure: procedure) } + let(:champ_pj) { dossier.champs.last } + + before do + champ_pj.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain") + end + + subject { DossierSerializer.new(dossier).serializable_hash } + + it "exposes the PJ in the legacy format" do + is_expected.to include( + types_de_piece_justificative: [ + { + "id" => type_pj.id, + "libelle" => type_pj.libelle, + "description" => type_pj.description, + "lien_demarche" => type_pj.lien_demarche, + "order_place" => type_pj.order_place + } + ], + pieces_justificatives: [ + { + "content_url" => champ_pj.for_api, + "created_at" => champ_pj.created_at.in_time_zone('UTC').iso8601(3), + "type_de_piece_justificative_id" => type_pj.id, + "user" => a_hash_including("id" => dossier.user.id) + } + ] + ) + end + + it "does not expose the PJ as a champ" do + expect(subject[:champs]).not_to include(a_hash_including(type_de_champ: a_hash_including(id: migrated_type_champ.id))) + end + end end diff --git a/spec/serializers/procedure_serializer_spec.rb b/spec/serializers/procedure_serializer_spec.rb index 487866665..be0d83669 100644 --- a/spec/serializers/procedure_serializer_spec.rb +++ b/spec/serializers/procedure_serializer_spec.rb @@ -8,4 +8,42 @@ describe ProcedureSerializer do is_expected.to include(state: "publiee") } end + + context 'when a type PJ was cloned to a type champ PJ' do + let(:original_procedure) do + p = create(:procedure, :published) + p.types_de_piece_justificative.create( + libelle: "Vidéo de votre demande de subvention", + description: "Pour optimiser vos chances, soignez la chorégraphie et privilégiez le chant polyphonique", + lien_demarche: "https://www.dance-academy.gouv.fr", + order_place: 0 + ) + p + end + + let(:procedure) { original_procedure.clone(original_procedure.administrateur, false) } + + let(:type_pj) { original_procedure.types_de_piece_justificative.first } + let(:migrated_type_champ) { procedure.types_de_champ.find_by(libelle: type_pj.libelle) } + + subject { ProcedureSerializer.new(procedure).serializable_hash } + + it "is exposed as a legacy type PJ" do + is_expected.to include( + types_de_piece_justificative: [ + { + "id" => type_pj.id, + "libelle" => type_pj.libelle, + "description" => type_pj.description, + "lien_demarche" => type_pj.lien_demarche, + "order_place" => type_pj.order_place + } + ] + ) + end + + it "is not exposed as a type de champ" do + expect(subject[:types_de_champ]).not_to include(a_hash_including(libelle: type_pj.libelle)) + end + end end diff --git a/spec/views/commencer/show.html.haml_spec.rb b/spec/views/commencer/show.html.haml_spec.rb new file mode 100644 index 000000000..274b55f45 --- /dev/null +++ b/spec/views/commencer/show.html.haml_spec.rb @@ -0,0 +1,76 @@ +require 'rails_helper' + +RSpec.describe 'commencer/show.html.haml', type: :view do + include Rails.application.routes.url_helpers + + let(:procedure) { create(:procedure, :with_service, :published) } + + before do + assign(:procedure, procedure) + if user + sign_in user + end + end + + subject { render } + + context 'when no user is signed in' do + let(:user) { nil } + + it 'renders sign-in and sign-up links' do + subject + expect(rendered).to have_link('Créer un compte') + expect(rendered).to have_link('J’ai déjà un compte') + end + end + + context 'when the user is already signed in' do + let(:user) { create :user } + + shared_examples_for 'it renders a link to create a new dossier' do |button_label| + it 'renders a link to create a new dossier' do + subject + expect(rendered).to have_link(button_label, href: new_dossier_url(procedure_id: procedure.id)) + end + end + + context 'and they don’t have any dossier on this procedure' do + it_behaves_like 'it renders a link to create a new dossier', 'Commencer la démarche' + end + + context 'and they have a pending draft' do + let!(:brouillon) { create(:dossier, user: user, procedure: procedure) } + + it_behaves_like 'it renders a link to create a new dossier', 'Commencer un nouveau dossier' + + it 'renders a link to resume the pending draft' do + subject + expect(rendered).to have_link('Continuer à remplir mon dossier', href: brouillon_dossier_path(brouillon)) + end + end + + context 'and they have a submitted dossier' do + let!(:brouillon) { create(:dossier, user: user, procedure: procedure) } + let!(:dossier) { create(:dossier, :en_construction, :for_individual, user: user, procedure: procedure) } + + it_behaves_like 'it renders a link to create a new dossier', 'Commencer un nouveau dossier' + + it 'renders a link to the submitted dossier' do + subject + expect(rendered).to have_link('Voir mon dossier', href: dossier_path(dossier)) + end + end + + context 'and they have several submitted dossiers' do + let!(:brouillon) { create(:dossier, user: user, procedure: procedure) } + let!(:dossiers) { create_list(:dossier, 2, :en_construction, :for_individual, user: user, procedure: procedure) } + + it_behaves_like 'it renders a link to create a new dossier', 'Commencer un nouveau dossier' + + it 'renders a link to the dossiers list' do + subject + expect(rendered).to have_link('Voir mes dossiers en cours', href: dossiers_path) + end + end + end +end diff --git a/spec/views/layouts/_new_header_spec.rb b/spec/views/layouts/_new_header_spec.rb index 9c81e7118..17980f07e 100644 --- a/spec/views/layouts/_new_header_spec.rb +++ b/spec/views/layouts/_new_header_spec.rb @@ -3,7 +3,6 @@ require 'spec_helper' describe 'layouts/_new_header.html.haml', type: :view do describe 'logo link' do before do - Flipflop::FeatureSet.current.test!.switch!(:support_form, true) sign_in user allow(controller).to receive(:nav_bar_profile).and_return(profile) render