commit
5a6882ab54
49 changed files with 425 additions and 76 deletions
|
@ -5,7 +5,7 @@ module Users
|
||||||
layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret]
|
layout 'procedure_context', only: [:identite, :update_identite, :siret, :update_siret]
|
||||||
|
|
||||||
ACTIONS_ALLOWED_TO_ANY_USER = [:index, :recherche, :new, :transferer_all]
|
ACTIONS_ALLOWED_TO_ANY_USER = [:index, :recherche, :new, :transferer_all]
|
||||||
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :demande, :messagerie, :brouillon, :update_brouillon, :modifier, :update, :create_commentaire]
|
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE = [:show, :demande, :messagerie, :brouillon, :update_brouillon, :modifier, :update, :create_commentaire, :papertrail]
|
||||||
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE_HIDDEN = [:restore]
|
ACTIONS_ALLOWED_TO_OWNER_OR_INVITE_HIDDEN = [:restore]
|
||||||
|
|
||||||
before_action :ensure_ownership!, except: ACTIONS_ALLOWED_TO_ANY_USER + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE_HIDDEN
|
before_action :ensure_ownership!, except: ACTIONS_ALLOWED_TO_ANY_USER + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE + ACTIONS_ALLOWED_TO_OWNER_OR_INVITE_HIDDEN
|
||||||
|
@ -69,6 +69,11 @@ module Users
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def papertrail
|
||||||
|
raise ActionController::BadRequest if dossier.brouillon?
|
||||||
|
@dossier = dossier
|
||||||
|
end
|
||||||
|
|
||||||
def identite
|
def identite
|
||||||
@dossier = dossier
|
@dossier = dossier
|
||||||
@user = current_user
|
@user = current_user
|
||||||
|
|
|
@ -9,7 +9,11 @@ class API::V2::Schema < GraphQL::Schema
|
||||||
context_class API::V2::Context
|
context_class API::V2::Context
|
||||||
|
|
||||||
def self.id_from_object(object, type_definition, ctx)
|
def self.id_from_object(object, type_definition, ctx)
|
||||||
object.to_typed_id
|
if object.is_a?(Hash)
|
||||||
|
object[:id]
|
||||||
|
else
|
||||||
|
object.to_typed_id
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.object_from_id(id, query_ctx)
|
def self.object_from_id(id, query_ctx)
|
||||||
|
|
|
@ -69,7 +69,7 @@ module Types
|
||||||
|
|
||||||
def usager
|
def usager
|
||||||
if object.user_deleted?
|
if object.user_deleted?
|
||||||
{ email: object.user_email_for(:display), id: -1 }
|
{ email: object.user_email_for(:display), id: '<deleted>' }
|
||||||
else
|
else
|
||||||
Loaders::Record.for(User).load(object.user_id)
|
Loaders::Record.for(User).load(object.user_id)
|
||||||
end
|
end
|
||||||
|
|
19
app/helpers/papertrail_helper.rb
Normal file
19
app/helpers/papertrail_helper.rb
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
module PapertrailHelper
|
||||||
|
def papertrail_requester_identity(dossier)
|
||||||
|
if dossier.etablissement.present?
|
||||||
|
raison_sociale_or_name(dossier.etablissement)
|
||||||
|
else
|
||||||
|
[dossier.individual.prenom, dossier.individual.nom.upcase].join(' ')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def papertrail_dossier_state(dossier)
|
||||||
|
raise "Dossiers in 'brouillon' state are not supported" if dossier.brouillon?
|
||||||
|
# i18n-tasks-use t('users.dossiers.papertrail.dossier_state.en_construction')
|
||||||
|
# i18n-tasks-use t('users.dossiers.papertrail.dossier_state.en_instruction')
|
||||||
|
# i18n-tasks-use t('users.dossiers.papertrail.dossier_state.accepte')
|
||||||
|
# i18n-tasks-use t('users.dossiers.papertrail.dossier_state.refuse')
|
||||||
|
# i18n-tasks-use t('users.dossiers.papertrail.dossier_state.sans_suite')
|
||||||
|
I18n.t("users.dossiers.papertrail.states.#{dossier.state}")
|
||||||
|
end
|
||||||
|
end
|
|
@ -31,5 +31,13 @@ module TurboStreamHelper
|
||||||
def focus_all(targets)
|
def focus_all(targets)
|
||||||
dispatch('dom:mutation', { action: :focus, targets: targets })
|
dispatch('dom:mutation', { action: :focus, targets: targets })
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def disable(target)
|
||||||
|
dispatch('dom:mutation', { action: :disable, target: target })
|
||||||
|
end
|
||||||
|
|
||||||
|
def enable(target)
|
||||||
|
dispatch('dom:mutation', { action: :enable, target: target })
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -38,7 +38,7 @@ export function useFeatureCollection(
|
||||||
features: callback(features)
|
features: callback(features)
|
||||||
}));
|
}));
|
||||||
httpRequest(url)
|
httpRequest(url)
|
||||||
.js()
|
.turbo()
|
||||||
.catch(() => null);
|
.catch(() => null);
|
||||||
},
|
},
|
||||||
[url, setFeatureCollection]
|
[url, setFeatureCollection]
|
||||||
|
|
|
@ -22,4 +22,19 @@ export class ApplicationController extends Controller {
|
||||||
target: document.documentElement
|
target: document.documentElement
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected on<HandlerEvent extends Event = Event>(
|
||||||
|
eventName: string,
|
||||||
|
handler: (event: HandlerEvent) => void
|
||||||
|
): void {
|
||||||
|
const disconnect = this.disconnect;
|
||||||
|
const callback = (event: Event): void => {
|
||||||
|
handler(event as HandlerEvent);
|
||||||
|
};
|
||||||
|
this.element.addEventListener(eventName, callback);
|
||||||
|
this.disconnect = () => {
|
||||||
|
this.element.removeEventListener(eventName, callback);
|
||||||
|
disconnect.call(this);
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ export class TurboEventController extends ApplicationController {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const MutationAction = z.enum(['show', 'hide', 'focus']);
|
const MutationAction = z.enum(['show', 'hide', 'focus', 'enable', 'disable']);
|
||||||
type MutationAction = z.infer<typeof MutationAction>;
|
type MutationAction = z.infer<typeof MutationAction>;
|
||||||
const Mutation = z.union([
|
const Mutation = z.union([
|
||||||
z.object({
|
z.object({
|
||||||
|
@ -55,6 +55,16 @@ const Mutations: Record<MutationAction, (mutation: Mutation) => void> = {
|
||||||
for (const element of findElements(mutation)) {
|
for (const element of findElements(mutation)) {
|
||||||
element.focus();
|
element.focus();
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
disable: (mutation) => {
|
||||||
|
for (const element of findElements<HTMLInputElement>(mutation)) {
|
||||||
|
element.disabled = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enable: (mutation) => {
|
||||||
|
for (const element of findElements<HTMLInputElement>(mutation)) {
|
||||||
|
element.disabled = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
22
app/javascript/controllers/turbo_input_controller.tsx
Normal file
22
app/javascript/controllers/turbo_input_controller.tsx
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
import { httpRequest } from '@utils';
|
||||||
|
|
||||||
|
import { ApplicationController } from './application_controller';
|
||||||
|
|
||||||
|
export class TurboInputController extends ApplicationController {
|
||||||
|
static values = {
|
||||||
|
url: String
|
||||||
|
};
|
||||||
|
|
||||||
|
declare readonly urlValue: string;
|
||||||
|
|
||||||
|
connect(): void {
|
||||||
|
this.on('input', () => this.debounce(this.load, 200));
|
||||||
|
}
|
||||||
|
|
||||||
|
private load(): void {
|
||||||
|
const target = this.element as HTMLInputElement;
|
||||||
|
const url = new URL(this.urlValue, document.baseURI);
|
||||||
|
url.searchParams.append(target.name, target.value);
|
||||||
|
httpRequest(url.toString()).turbo();
|
||||||
|
}
|
||||||
|
}
|
|
@ -8,7 +8,6 @@ import * as Turbo from '@hotwired/turbo';
|
||||||
import '../shared/activestorage/ujs';
|
import '../shared/activestorage/ujs';
|
||||||
import '../shared/remote-poller';
|
import '../shared/remote-poller';
|
||||||
import '../shared/safari-11-file-xhr-workaround';
|
import '../shared/safari-11-file-xhr-workaround';
|
||||||
import '../shared/remote-input';
|
|
||||||
import '../shared/franceconnect';
|
import '../shared/franceconnect';
|
||||||
import '../shared/toggle-target';
|
import '../shared/toggle-target';
|
||||||
import '../shared/ujs-error-handling';
|
import '../shared/ujs-error-handling';
|
||||||
|
@ -19,6 +18,7 @@ import {
|
||||||
} from '../controllers/react_controller';
|
} from '../controllers/react_controller';
|
||||||
import { TurboEventController } from '../controllers/turbo_event_controller';
|
import { TurboEventController } from '../controllers/turbo_event_controller';
|
||||||
import { GeoAreaController } from '../controllers/geo_area_controller';
|
import { GeoAreaController } from '../controllers/geo_area_controller';
|
||||||
|
import { TurboInputController } from '../controllers/turbo_input_controller';
|
||||||
|
|
||||||
import '../new_design/dropdown';
|
import '../new_design/dropdown';
|
||||||
import '../new_design/form-validation';
|
import '../new_design/form-validation';
|
||||||
|
@ -96,6 +96,7 @@ const Stimulus = Application.start();
|
||||||
Stimulus.register('react', ReactController);
|
Stimulus.register('react', ReactController);
|
||||||
Stimulus.register('turbo-event', TurboEventController);
|
Stimulus.register('turbo-event', TurboEventController);
|
||||||
Stimulus.register('geo-area', GeoAreaController);
|
Stimulus.register('geo-area', GeoAreaController);
|
||||||
|
Stimulus.register('turbo-input', TurboInputController);
|
||||||
|
|
||||||
// Expose globals
|
// Expose globals
|
||||||
window.DS = window.DS || DS;
|
window.DS = window.DS || DS;
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
import { delegate, fire, debounce } from '@utils';
|
|
||||||
|
|
||||||
const remote = 'data-remote';
|
|
||||||
const inputChangeSelector = `input[${remote}], textarea[${remote}]`;
|
|
||||||
|
|
||||||
// This is a patch for ujs remote handler. Its purpose is to add
|
|
||||||
// a debounced input listener.
|
|
||||||
function handleRemote(event) {
|
|
||||||
const element = this;
|
|
||||||
|
|
||||||
if (isRemote(element)) {
|
|
||||||
fire(element, 'change', event);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRemote(element) {
|
|
||||||
const value = element.getAttribute(remote);
|
|
||||||
return value && value !== 'false';
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate('input', inputChangeSelector, debounce(handleRemote, 200));
|
|
|
@ -148,7 +148,7 @@ class Champ < ApplicationRecord
|
||||||
# predictable input name.
|
# predictable input name.
|
||||||
def input_name
|
def input_name
|
||||||
if parent_id
|
if parent_id
|
||||||
"#{parent.input_name}[#{champs_attributes_accessor}][#{id}]"
|
"#{parent.input_name}[champs_attributes][#{id}]"
|
||||||
else
|
else
|
||||||
"dossier[#{champs_attributes_accessor}][#{id}]"
|
"dossier[#{champs_attributes_accessor}][#{id}]"
|
||||||
end
|
end
|
||||||
|
|
|
@ -12,7 +12,6 @@
|
||||||
# updated_at :datetime not null
|
# updated_at :datetime not null
|
||||||
# bill_signature_id :bigint
|
# bill_signature_id :bigint
|
||||||
# dossier_id :bigint
|
# dossier_id :bigint
|
||||||
# instructeur_id :bigint
|
|
||||||
#
|
#
|
||||||
class DossierOperationLog < ApplicationRecord
|
class DossierOperationLog < ApplicationRecord
|
||||||
self.ignored_columns = [:instructeur_id]
|
self.ignored_columns = [:instructeur_id]
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
<%= render_flash(timeout: 5000, fixed: true) %>
|
|
||||||
|
|
||||||
<%= render_to_element("##{@champ.input_group_id} .geo-areas",
|
|
||||||
partial: 'shared/champs/carte/geo_areas',
|
|
||||||
locals: { champ: @champ, editing: true }) %>
|
|
||||||
|
|
||||||
<% if @focus %>
|
|
||||||
<%= fire_event('map:feature:focus', { bbox: @champ.bounding_box }.to_json) %>
|
|
||||||
<% end %>
|
|
4
app/views/champs/carte/index.turbo_stream.haml
Normal file
4
app/views/champs/carte/index.turbo_stream.haml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
= turbo_stream.update dom_id(@champ, :geo_areas), partial: 'shared/champs/carte/geo_areas', locals: { champ: @champ, editing: true }
|
||||||
|
|
||||||
|
- if @focus
|
||||||
|
= turbo_stream.dispatch 'map:feature:focus', bbox: @champ.bounding_box
|
|
@ -1,3 +0,0 @@
|
||||||
<%= render_to_element("##{@champ.input_group_id} .help-block",
|
|
||||||
partial: 'shared/champs/dossier_link/help_block',
|
|
||||||
locals: { id: @linked_dossier_id }) %>
|
|
1
app/views/champs/dossier_link/show.turbo_stream.haml
Normal file
1
app/views/champs/dossier_link/show.turbo_stream.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
= turbo_stream.update dom_id(@champ, :help_block), partial: 'shared/champs/dossier_link/help_block', locals: { id: @linked_dossier_id }
|
|
@ -1,3 +0,0 @@
|
||||||
<%= render_to_element("##{@champ.input_group_id} .siret-info",
|
|
||||||
partial: 'shared/champs/siret/etablissement',
|
|
||||||
locals: { siret: @siret, etablissement: @etablissement }) %>
|
|
1
app/views/champs/siret/show.turbo_stream.haml
Normal file
1
app/views/champs/siret/show.turbo_stream.haml
Normal file
|
@ -0,0 +1 @@
|
||||||
|
= turbo_stream.update dom_id(@champ, :siret_info), partial: 'shared/champs/siret/etablissement', locals: { siret: @siret, etablissement: @etablissement }
|
|
@ -1,4 +1,4 @@
|
||||||
= form.password_field :password, autofocus: true, autocomplete: 'off', placeholder: 'Mot de passe', data: { remote: test_complexity, url: show_password_complexity_path }
|
= form.password_field :password, autofocus: true, autocomplete: 'off', placeholder: 'Mot de passe', data: { controller: test_complexity ? 'turbo-input' : false, turbo_input_url_value: show_password_complexity_path }
|
||||||
|
|
||||||
- if test_complexity
|
- if test_complexity
|
||||||
#complexity-bar.password-complexity
|
#complexity-bar.password-complexity
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
<%= render_to_element('#complexity-label', partial: 'label', outer: true) %>
|
|
||||||
<%= render_to_element('#complexity-bar', partial: 'bar', outer: true) %>
|
|
||||||
<%= raw("document.querySelector('#submit-password').disabled = #{@score < @min_complexity || @length < @min_length};") %>
|
|
6
app/views/password_complexity/show.turbo_stream.haml
Normal file
6
app/views/password_complexity/show.turbo_stream.haml
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
= turbo_stream.replace 'complexity-label', partial: 'label'
|
||||||
|
= turbo_stream.replace 'complexity-bar', partial: 'bar'
|
||||||
|
- if @score < @min_complexity || @length < @min_length
|
||||||
|
= turbo_stream.disable 'submit-password'
|
||||||
|
- else
|
||||||
|
= turbo_stream.enable 'submit-password'
|
|
@ -1,4 +1,4 @@
|
||||||
= react_component("MapEditor", featureCollection: champ.to_feature_collection, url: champs_carte_features_path(champ), options: champ.render_options)
|
= react_component("MapEditor", featureCollection: champ.to_feature_collection, url: champs_carte_features_path(champ), options: champ.render_options)
|
||||||
|
|
||||||
.geo-areas
|
.geo-areas{ id: dom_id(champ, :geo_areas) }
|
||||||
= render partial: 'shared/champs/carte/geo_areas', locals: { champ: champ, editing: true }
|
= render partial: 'shared/champs/carte/geo_areas', locals: { champ: champ, editing: true }
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
placeholder: "Numéro de dossier",
|
placeholder: "Numéro de dossier",
|
||||||
autocomplete: 'off',
|
autocomplete: 'off',
|
||||||
required: champ.mandatory?,
|
required: champ.mandatory?,
|
||||||
data: { remote: true, url: champs_dossier_link_path(champ.id) }
|
data: { controller: 'turbo-input', turbo_input_url_value: champs_dossier_link_path(champ.id) }
|
||||||
|
|
||||||
.help-block
|
.help-block{ id: dom_id(champ, :help_block) }
|
||||||
= render partial: 'shared/champs/dossier_link/help_block', locals: { id: champ.value }
|
= render partial: 'shared/champs/dossier_link/help_block', locals: { id: champ.value }
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
id: champ.input_id,
|
id: champ.input_id,
|
||||||
aria: { describedby: champ.describedby_id },
|
aria: { describedby: champ.describedby_id },
|
||||||
placeholder: champ.libelle,
|
placeholder: champ.libelle,
|
||||||
data: { remote: true, debounce: true, url: champs_siret_path(champ.id), spinner: true },
|
data: { controller: 'turbo-input', turbo_input_url_value: champs_siret_path(champ.id) },
|
||||||
required: champ.mandatory?,
|
required: champ.mandatory?,
|
||||||
pattern: "[0-9]{14}",
|
pattern: "[0-9]{14}",
|
||||||
title: "Le numéro de SIRET doit comporter exactement 14 chiffres"
|
title: "Le numéro de SIRET doit comporter exactement 14 chiffres"
|
||||||
.spinner.right.hidden
|
.spinner.right.hidden
|
||||||
.siret-info
|
.siret-info{ id: dom_id(champ, :siret_info) }
|
||||||
- if champ.etablissement.present?
|
- if champ.etablissement.present?
|
||||||
= render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement }
|
= render partial: 'shared/dossiers/editable_champs/etablissement_titre', locals: { etablissement: champ.etablissement }
|
||||||
|
|
99
app/views/users/dossiers/papertrail.pdf.prawn
Normal file
99
app/views/users/dossiers/papertrail.pdf.prawn
Normal file
|
@ -0,0 +1,99 @@
|
||||||
|
require 'prawn/measurement_extensions'
|
||||||
|
|
||||||
|
#----- A4 page size
|
||||||
|
page_size = 'A4'
|
||||||
|
page_width = 595
|
||||||
|
|
||||||
|
#----- margins
|
||||||
|
top_margin = 20
|
||||||
|
right_margin = 20
|
||||||
|
bottom_margin = 20
|
||||||
|
left_margin = 20
|
||||||
|
|
||||||
|
header_width = page_width - left_margin - right_margin
|
||||||
|
body_width = 400
|
||||||
|
|
||||||
|
body_left_margin = (page_width - body_width - left_margin - right_margin) / 2
|
||||||
|
|
||||||
|
prawn_document(margin: [top_margin, right_margin, bottom_margin, left_margin], page_size: page_size) do |pdf|
|
||||||
|
pdf.font_families.update('marianne' => {
|
||||||
|
normal: Rails.root.join('lib/prawn/fonts/marianne/marianne-regular.ttf'),
|
||||||
|
bold: Rails.root.join('lib/prawn/fonts/marianne/marianne-bold.ttf')
|
||||||
|
})
|
||||||
|
pdf.font 'marianne'
|
||||||
|
|
||||||
|
grey = '555555'
|
||||||
|
black = '333333'
|
||||||
|
|
||||||
|
pdf.float do
|
||||||
|
pdf.svg IO.read(DOSSIER_DEPOSIT_RECEIPT_LOGO_SRC), height: 64
|
||||||
|
end
|
||||||
|
|
||||||
|
pdf.bounding_box([110, pdf.cursor - 18], width: header_width - 200) do
|
||||||
|
pdf.fill_color black
|
||||||
|
pdf.text APPLICATION_NAME, size: 20, style: :bold
|
||||||
|
|
||||||
|
pdf.fill_color grey
|
||||||
|
pdf.text t('.receipt'), size: 14
|
||||||
|
end
|
||||||
|
|
||||||
|
pdf.bounding_box([body_left_margin, pdf.cursor - 20], width: body_width) do
|
||||||
|
pdf.fill_color black
|
||||||
|
pdf.pad_top(40) { pdf.text @dossier.procedure.libelle, size: 14, character_spacing: -0.2, align: :center }
|
||||||
|
|
||||||
|
pdf.fill_color grey
|
||||||
|
description = t('.description', user_name: papertrail_requester_identity(@dossier), procedure: @dossier.procedure.libelle, date: l(@dossier.created_at, format: '%e %B %Y'))
|
||||||
|
pdf.pad_top(30) { pdf.text description, size: 10, character_spacing: -0.2, align: :left }
|
||||||
|
|
||||||
|
pdf.fill_color black
|
||||||
|
pdf.pad_top(30) { pdf.text t('views.shared.dossiers.demande.requester_identity'), size: 14, character_spacing: -0.2, align: :justify }
|
||||||
|
|
||||||
|
if @dossier.individual.present?
|
||||||
|
pdf.pad_top(7) do
|
||||||
|
pdf.fill_color grey
|
||||||
|
pdf.text "#{Individual.human_attribute_name(:prenom)} : #{@dossier.individual.prenom}", size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
pdf.text "#{Individual.human_attribute_name(:nom)} : #{@dossier.individual.nom.upcase}", size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @dossier.etablissement.present?
|
||||||
|
pdf.pad_top(7) do
|
||||||
|
pdf.fill_color grey
|
||||||
|
pdf.text "Dénomination : " + raison_sociale_or_name(@dossier.etablissement), size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
pdf.text "SIRET : " + @dossier.etablissement.siret, size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pdf.fill_color black
|
||||||
|
pdf.pad_top(30) { pdf.text Dossier.model_name.human, size: 14, character_spacing: -0.2, align: :justify }
|
||||||
|
|
||||||
|
pdf.fill_color grey
|
||||||
|
pdf.pad_top(7) do
|
||||||
|
pdf.text "#{Dossier.human_attribute_name(:id)} : #{@dossier.id.to_s}", size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
pdf.text t('.file_submitted_at') + ' : ' + l(@dossier.en_construction_at, format: '%e %B %Y'), size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
pdf.text t('.dossier_state') + ' : ' + papertrail_dossier_state(@dossier), size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
end
|
||||||
|
|
||||||
|
service = @dossier.procedure.service
|
||||||
|
if service.present?
|
||||||
|
pdf.fill_color black
|
||||||
|
pdf.pad_top(30) { pdf.text t('.administrative_service'), size: 14, character_spacing: -0.2, align: :justify }
|
||||||
|
|
||||||
|
pdf.fill_color grey
|
||||||
|
pdf.pad_top(7) do
|
||||||
|
pdf.text "#{Service.model_name.human} : " + [service.nom, service.organisme].join(", "), size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
pdf.text "#{Service.human_attribute_name(:adresse)} : #{service.adresse}", size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
pdf.text "#{Service.human_attribute_name(:email)} : #{service.email}", size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
if service.telephone.present?
|
||||||
|
pdf.text "#{Service.human_attribute_name(:telephone)} : #{service.telephone}", size: 10, character_spacing: -0.2, align: :justify
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
pdf.fill_color black
|
||||||
|
pdf.pad_top(100) do
|
||||||
|
pdf.text t('.generated_at', date: l(Time.zone.now.to_date, format: :long)), size: 10, character_spacing: -0.2, align: :right
|
||||||
|
pdf.text t('.signature', app_name: APPLICATION_NAME), size: 10, character_spacing: -0.2, align: :right
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,5 +9,8 @@
|
||||||
.container
|
.container
|
||||||
= render partial: 'users/dossiers/show/status_overview', locals: { dossier: @dossier }
|
= render partial: 'users/dossiers/show/status_overview', locals: { dossier: @dossier }
|
||||||
|
|
||||||
|
- if @dossier.procedure.feature_enabled?(:procedure_dossier_papertrail)
|
||||||
|
= render partial: 'users/dossiers/show/papertrail', locals: { dossier: @dossier }
|
||||||
|
|
||||||
- if !@dossier.termine?
|
- if !@dossier.termine?
|
||||||
= render partial: 'users/dossiers/show/latest_message', locals: { dossier: @dossier }
|
= render partial: 'users/dossiers/show/latest_message', locals: { dossier: @dossier }
|
||||||
|
|
4
app/views/users/dossiers/show/_papertrail.html.haml
Normal file
4
app/views/users/dossiers/show/_papertrail.html.haml
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
.papertrail.mb-2
|
||||||
|
= link_to papertrail_dossier_url(dossier, format: :pdf), class: "button", download: t('.filename'), target: "_blank" do
|
||||||
|
%span.icon.justificatif
|
||||||
|
= t('.get_papertrail')
|
|
@ -68,6 +68,9 @@ DS_ENV="staging"
|
||||||
# Instance customization: Procedure default logo ---> to be put in "app/assets/images"
|
# Instance customization: Procedure default logo ---> to be put in "app/assets/images"
|
||||||
# PROCEDURE_DEFAULT_LOGO_SRC="republique-francaise-logo.svg"
|
# PROCEDURE_DEFAULT_LOGO_SRC="republique-francaise-logo.svg"
|
||||||
|
|
||||||
|
# Instance customization: Deposit receipt logo ---> to be put in "app/assets/images"
|
||||||
|
# DOSSIER_DEPOSIT_RECEIPT_LOGO_SRC="app/assets/images/republique-francaise-logo.svg"
|
||||||
|
|
||||||
# Instance customization: PDF export logo ---> to be put in "app/assets/images"
|
# Instance customization: PDF export logo ---> to be put in "app/assets/images"
|
||||||
# DOSSIER_PDF_EXPORT_LOGO_SRC="app/assets/images/header/logo-ds-wide.svg"
|
# DOSSIER_PDF_EXPORT_LOGO_SRC="app/assets/images/header/logo-ds-wide.svg"
|
||||||
|
|
||||||
|
|
|
@ -32,7 +32,8 @@ features = [
|
||||||
:hide_instructeur_email,
|
:hide_instructeur_email,
|
||||||
:procedure_revisions,
|
:procedure_revisions,
|
||||||
:procedure_routage_api,
|
:procedure_routage_api,
|
||||||
:procedure_process_expired_dossiers_termine
|
:procedure_process_expired_dossiers_termine,
|
||||||
|
:procedure_dossier_papertrail
|
||||||
]
|
]
|
||||||
|
|
||||||
def database_exists?
|
def database_exists?
|
||||||
|
|
|
@ -16,5 +16,8 @@ MAILER_FOOTER_LOGO_SRC = ENV.fetch("MAILER_FOOTER_LOGO_SRC", "mailer/instructeur
|
||||||
# Default logo of a procedure
|
# Default logo of a procedure
|
||||||
PROCEDURE_DEFAULT_LOGO_SRC = ENV.fetch("PROCEDURE_DEFAULT_LOGO_SRC", "republique-francaise-logo.svg")
|
PROCEDURE_DEFAULT_LOGO_SRC = ENV.fetch("PROCEDURE_DEFAULT_LOGO_SRC", "republique-francaise-logo.svg")
|
||||||
|
|
||||||
|
# Deposit receipt logo
|
||||||
|
DOSSIER_DEPOSIT_RECEIPT_LOGO_SRC = ENV.fetch("DOSSIER_DEPOSIT_RECEIPT_LOGO_SRC", "app/assets/images/republique-francaise-logo.svg")
|
||||||
|
|
||||||
# Logo in PDF export of a "Dossier"
|
# Logo in PDF export of a "Dossier"
|
||||||
DOSSIER_PDF_EXPORT_LOGO_SRC = ENV.fetch("DOSSIER_PDF_EXPORT_LOGO_SRC", "app/assets/images/header/logo-ds-wide.svg")
|
DOSSIER_PDF_EXPORT_LOGO_SRC = ENV.fetch("DOSSIER_PDF_EXPORT_LOGO_SRC", "app/assets/images/header/logo-ds-wide.svg")
|
||||||
|
|
|
@ -453,6 +453,24 @@ en:
|
||||||
identity_saved: "Identity data is registred"
|
identity_saved: "Identity data is registred"
|
||||||
attestation:
|
attestation:
|
||||||
no_longer_available: "The certificate is no longer available on this file."
|
no_longer_available: "The certificate is no longer available on this file."
|
||||||
|
show:
|
||||||
|
papertrail:
|
||||||
|
get_papertrail: "Get a deposit receipt"
|
||||||
|
filename: "deposit-receipt.pdf"
|
||||||
|
papertrail:
|
||||||
|
receipt: "Deposit receipt"
|
||||||
|
description: "This document attests that on the %{date}, %{user_name} submitted a file on the procedure “%{procedure}”."
|
||||||
|
file_submitted_at: "File submission date"
|
||||||
|
dossier_state: "File status"
|
||||||
|
states:
|
||||||
|
en_construction: "submitted, pending processing"
|
||||||
|
en_instruction: "processing"
|
||||||
|
accepte: "accepted"
|
||||||
|
refuse: "declined"
|
||||||
|
sans suite: "closed, no further action"
|
||||||
|
administrative_service: "Administrative department"
|
||||||
|
generated_at: "Made on %{date},"
|
||||||
|
signature: "%{app_name}"
|
||||||
instructeurs:
|
instructeurs:
|
||||||
dossiers:
|
dossiers:
|
||||||
deleted_by_instructeur: "The folder has been deleted"
|
deleted_by_instructeur: "The folder has been deleted"
|
||||||
|
|
|
@ -461,6 +461,24 @@ fr:
|
||||||
identity_saved: "Identité enregistrée"
|
identity_saved: "Identité enregistrée"
|
||||||
attestation:
|
attestation:
|
||||||
no_longer_available: "L’attestation n'est plus disponible sur ce dossier."
|
no_longer_available: "L’attestation n'est plus disponible sur ce dossier."
|
||||||
|
papertrail:
|
||||||
|
receipt: "Accusé de dépôt"
|
||||||
|
description: "Ce document atteste que %{user_name} a déposé le %{date} un dossier sur la démarche « %{procedure} »."
|
||||||
|
file_submitted_at: "Dossier déposé le"
|
||||||
|
dossier_state: "État du dossier"
|
||||||
|
states:
|
||||||
|
en_construction: "déposé, en attente d’examen par l’administration"
|
||||||
|
en_instruction: "en cours d’instruction par l’administration"
|
||||||
|
accepte: "accepté"
|
||||||
|
refuse: "refusé"
|
||||||
|
sans suite: "classé sans suite"
|
||||||
|
administrative_service: "Service administratif"
|
||||||
|
generated_at: "Fait le %{date},"
|
||||||
|
signature: "La direction de %{app_name}"
|
||||||
|
show:
|
||||||
|
papertrail:
|
||||||
|
get_papertrail: "Obtenir une attestation de dépôt de dossier"
|
||||||
|
filename: "attestation-de-depot.pdf"
|
||||||
instructeurs:
|
instructeurs:
|
||||||
dossiers:
|
dossiers:
|
||||||
deleted_by_instructeur: "Le dossier a bien été supprimé de votre interface"
|
deleted_by_instructeur: "Le dossier a bien été supprimé de votre interface"
|
||||||
|
|
|
@ -6,6 +6,7 @@ en:
|
||||||
other: "Files"
|
other: "Files"
|
||||||
attributes:
|
attributes:
|
||||||
dossier:
|
dossier:
|
||||||
|
id: "File number"
|
||||||
state: "State"
|
state: "State"
|
||||||
dossier/state: &state
|
dossier/state: &state
|
||||||
brouillon: "Draft"
|
brouillon: "Draft"
|
||||||
|
|
|
@ -6,6 +6,7 @@ fr:
|
||||||
other: "Dossiers"
|
other: "Dossiers"
|
||||||
attributes:
|
attributes:
|
||||||
dossier:
|
dossier:
|
||||||
|
id: "Numéro de dossier"
|
||||||
montant_projet: 'Le montant du projet'
|
montant_projet: 'Le montant du projet'
|
||||||
montant_aide_demande: "Le montant d’aide demandée"
|
montant_aide_demande: "Le montant d’aide demandée"
|
||||||
date_previsionnelle: "La date de début prévisionnelle"
|
date_previsionnelle: "La date de début prévisionnelle"
|
||||||
|
|
11
config/locales/models/service/en.yml
Normal file
11
config/locales/models/service/en.yml
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
en:
|
||||||
|
activerecord:
|
||||||
|
models:
|
||||||
|
service:
|
||||||
|
one: 'Service'
|
||||||
|
other: 'Services'
|
||||||
|
attributes:
|
||||||
|
service:
|
||||||
|
adresse: 'Mail address'
|
||||||
|
email: 'Email'
|
||||||
|
telephone: 'Phone'
|
|
@ -1,4 +1,14 @@
|
||||||
fr:
|
fr:
|
||||||
|
activerecord:
|
||||||
|
models:
|
||||||
|
service:
|
||||||
|
one: 'Service'
|
||||||
|
other: 'Services'
|
||||||
|
attributes:
|
||||||
|
service:
|
||||||
|
adresse: 'Adresse postale'
|
||||||
|
email: 'Email de contact'
|
||||||
|
telephone: 'Téléphone'
|
||||||
type_organisme:
|
type_organisme:
|
||||||
administration_centrale: 'Administration centrale'
|
administration_centrale: 'Administration centrale'
|
||||||
association: 'Association'
|
association: 'Association'
|
||||||
|
|
|
@ -273,6 +273,7 @@ Rails.application.routes.draw do
|
||||||
patch 'restore', to: 'dossiers#restore'
|
patch 'restore', to: 'dossiers#restore'
|
||||||
get 'attestation'
|
get 'attestation'
|
||||||
get 'transferer', to: 'dossiers#transferer'
|
get 'transferer', to: 'dossiers#transferer'
|
||||||
|
get 'papertrail', format: :pdf
|
||||||
end
|
end
|
||||||
|
|
||||||
collection do
|
collection do
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class RemoveColumnInstructeurIdFromDossierOperationLog < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
safety_assured { remove_column :dossier_operation_logs, :instructeur_id }
|
||||||
|
end
|
||||||
|
end
|
|
@ -267,13 +267,11 @@ ActiveRecord::Schema.define(version: 2022_04_26_140107) do
|
||||||
t.text "digest"
|
t.text "digest"
|
||||||
t.bigint "dossier_id"
|
t.bigint "dossier_id"
|
||||||
t.datetime "executed_at"
|
t.datetime "executed_at"
|
||||||
t.bigint "instructeur_id"
|
|
||||||
t.datetime "keep_until"
|
t.datetime "keep_until"
|
||||||
t.string "operation", null: false
|
t.string "operation", null: false
|
||||||
t.datetime "updated_at", null: false
|
t.datetime "updated_at", null: false
|
||||||
t.index ["bill_signature_id"], name: "index_dossier_operation_logs_on_bill_signature_id"
|
t.index ["bill_signature_id"], name: "index_dossier_operation_logs_on_bill_signature_id"
|
||||||
t.index ["dossier_id"], name: "index_dossier_operation_logs_on_dossier_id"
|
t.index ["dossier_id"], name: "index_dossier_operation_logs_on_dossier_id"
|
||||||
t.index ["instructeur_id"], name: "index_dossier_operation_logs_on_instructeur_id"
|
|
||||||
t.index ["keep_until"], name: "index_dossier_operation_logs_on_keep_until"
|
t.index ["keep_until"], name: "index_dossier_operation_logs_on_keep_until"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -874,7 +872,6 @@ ActiveRecord::Schema.define(version: 2022_04_26_140107) do
|
||||||
add_foreign_key "commentaires", "dossiers"
|
add_foreign_key "commentaires", "dossiers"
|
||||||
add_foreign_key "commentaires", "experts"
|
add_foreign_key "commentaires", "experts"
|
||||||
add_foreign_key "dossier_operation_logs", "bill_signatures"
|
add_foreign_key "dossier_operation_logs", "bill_signatures"
|
||||||
add_foreign_key "dossier_operation_logs", "instructeurs"
|
|
||||||
add_foreign_key "dossier_transfer_logs", "dossiers"
|
add_foreign_key "dossier_transfer_logs", "dossiers"
|
||||||
add_foreign_key "dossiers", "dossier_transfers"
|
add_foreign_key "dossiers", "dossier_transfers"
|
||||||
add_foreign_key "dossiers", "groupe_instructeurs"
|
add_foreign_key "dossiers", "groupe_instructeurs"
|
||||||
|
|
|
@ -117,7 +117,7 @@ describe Champs::CarteController, type: :controller do
|
||||||
render_views
|
render_views
|
||||||
|
|
||||||
before do
|
before do
|
||||||
get :index, params: params, format: :js, xhr: true
|
get :index, params: params, format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'without focus' do
|
context 'without focus' do
|
||||||
|
@ -126,7 +126,7 @@ describe Champs::CarteController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates the list' do
|
it 'updates the list' do
|
||||||
expect(response.body).not_to include("DS.fire('map:feature:focus'")
|
expect(response.body).not_to include("map:feature:focus")
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -140,7 +140,8 @@ describe Champs::CarteController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'updates the list and focuses the map' do
|
it 'updates the list and focuses the map' do
|
||||||
expect(response.body).to include("DS.fire('map:feature:focus'")
|
expect(response.body).to include(ActionView::RecordIdentifier.dom_id(champ, :geo_areas))
|
||||||
|
expect(response.body).to include("map:feature:focus")
|
||||||
expect(response.status).to eq 200
|
expect(response.status).to eq 200
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,33 +27,33 @@ describe Champs::DossierLinkController, type: :controller do
|
||||||
|
|
||||||
context 'when the dossier exist' do
|
context 'when the dossier exist' do
|
||||||
before do
|
before do
|
||||||
get :show, params: params, format: :js, xhr: true
|
get :show, params: params, format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders the procedure name' do
|
it 'renders the procedure name' do
|
||||||
expect(response.body).to include('Dossier en brouillon')
|
expect(response.body).to include('Dossier en brouillon')
|
||||||
expect(response.body).to include(procedure.libelle)
|
expect(response.body).to include(procedure.libelle)
|
||||||
expect(response.body).to include(procedure.organisation)
|
expect(response.body).to include(procedure.organisation)
|
||||||
expect(response.body).to include("##{champ.input_group_id} .help-block")
|
expect(response.body).to include(ActionView::RecordIdentifier.dom_id(champ, :help_block))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the dossier does not exist' do
|
context 'when the dossier does not exist' do
|
||||||
let(:dossier_id) { '13' }
|
let(:dossier_id) { '13' }
|
||||||
before do
|
before do
|
||||||
get :show, params: params, format: :js, xhr: true
|
get :show, params: params, format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'renders error message' do
|
it 'renders error message' do
|
||||||
expect(response.body).to include('Ce dossier est inconnu')
|
expect(response.body).to include('Ce dossier est inconnu')
|
||||||
expect(response.body).to include("##{champ.input_group_id} .help-block")
|
expect(response.body).to include(ActionView::RecordIdentifier.dom_id(champ, :help_block))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user is not connected' do
|
context 'when user is not connected' do
|
||||||
before do
|
before do
|
||||||
get :show, params: { champ_id: champ.id }, format: :js, xhr: true
|
get :show, params: { champ_id: champ.id }, format: :turbo_stream
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(response.code).to eq('401') }
|
it { expect(response.code).to eq('401') }
|
||||||
|
|
|
@ -37,7 +37,7 @@ describe Champs::SiretController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the SIRET is empty' do
|
context 'when the SIRET is empty' do
|
||||||
subject! { get :show, params: params, format: :js, xhr: true }
|
subject! { get :show, params: params, format: :turbo_stream }
|
||||||
|
|
||||||
it 'clears the etablissement and SIRET on the model' do
|
it 'clears the etablissement and SIRET on the model' do
|
||||||
champ.reload
|
champ.reload
|
||||||
|
@ -46,15 +46,14 @@ describe Champs::SiretController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'clears any information or error message' do
|
it 'clears any information or error message' do
|
||||||
expect(response.body).to include("##{champ.input_group_id} .siret-info")
|
expect(response.body).to include(ActionView::RecordIdentifier.dom_id(champ, :siret_info))
|
||||||
expect(response.body).to include('innerHTML = ""')
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the SIRET is invalid' do
|
context 'when the SIRET is invalid' do
|
||||||
let(:siret) { '1234' }
|
let(:siret) { '1234' }
|
||||||
|
|
||||||
subject! { get :show, params: params, format: :js, xhr: true }
|
subject! { get :show, params: params, format: :turbo_stream }
|
||||||
|
|
||||||
it 'clears the etablissement and SIRET on the model' do
|
it 'clears the etablissement and SIRET on the model' do
|
||||||
champ.reload
|
champ.reload
|
||||||
|
@ -71,7 +70,7 @@ describe Champs::SiretController, type: :controller do
|
||||||
let(:siret) { '82161143100015' }
|
let(:siret) { '82161143100015' }
|
||||||
let(:api_etablissement_status) { 503 }
|
let(:api_etablissement_status) { 503 }
|
||||||
|
|
||||||
subject! { get :show, params: params, format: :js, xhr: true }
|
subject! { get :show, params: params, format: :turbo_stream }
|
||||||
|
|
||||||
it 'clears the etablissement and SIRET on the model' do
|
it 'clears the etablissement and SIRET on the model' do
|
||||||
champ.reload
|
champ.reload
|
||||||
|
@ -88,7 +87,7 @@ describe Champs::SiretController, type: :controller do
|
||||||
let(:siret) { '00000000000000' }
|
let(:siret) { '00000000000000' }
|
||||||
let(:api_etablissement_status) { 404 }
|
let(:api_etablissement_status) { 404 }
|
||||||
|
|
||||||
subject! { get :show, params: params, format: :js, xhr: true }
|
subject! { get :show, params: params, format: :turbo_stream }
|
||||||
|
|
||||||
it 'clears the etablissement and SIRET on the model' do
|
it 'clears the etablissement and SIRET on the model' do
|
||||||
champ.reload
|
champ.reload
|
||||||
|
@ -106,7 +105,7 @@ describe Champs::SiretController, type: :controller do
|
||||||
let(:api_etablissement_status) { 200 }
|
let(:api_etablissement_status) { 200 }
|
||||||
let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
|
let(:api_etablissement_body) { File.read('spec/fixtures/files/api_entreprise/etablissements.json') }
|
||||||
|
|
||||||
subject! { get :show, params: params, format: :js, xhr: true }
|
subject! { get :show, params: params, format: :turbo_stream }
|
||||||
|
|
||||||
it 'populates the etablissement and SIRET on the model' do
|
it 'populates the etablissement and SIRET on the model' do
|
||||||
champ.reload
|
champ.reload
|
||||||
|
@ -119,7 +118,7 @@ describe Champs::SiretController, type: :controller do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when user is not signed in' do
|
context 'when user is not signed in' do
|
||||||
subject! { get :show, params: { champ_id: champ.id }, format: :js, xhr: true }
|
subject! { get :show, params: { champ_id: champ.id }, format: :turbo_stream }
|
||||||
|
|
||||||
it { expect(response.code).to eq('401') }
|
it { expect(response.code).to eq('401') }
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,7 +4,7 @@ describe PasswordComplexityController, type: :controller do
|
||||||
{ user: { password: 'moderately complex password' } }
|
{ user: { password: 'moderately complex password' } }
|
||||||
end
|
end
|
||||||
|
|
||||||
subject { get :show, format: :js, params: params, xhr: true }
|
subject { get :show, format: :turbo_stream, params: params }
|
||||||
|
|
||||||
it 'computes a password score' do
|
it 'computes a password score' do
|
||||||
subject
|
subject
|
||||||
|
@ -27,8 +27,8 @@ describe PasswordComplexityController, type: :controller do
|
||||||
|
|
||||||
it 'renders Javascript that updates the password complexity meter' do
|
it 'renders Javascript that updates the password complexity meter' do
|
||||||
subject
|
subject
|
||||||
expect(response.body).to include('#complexity-label')
|
expect(response.body).to include('complexity-label')
|
||||||
expect(response.body).to include('#complexity-bar')
|
expect(response.body).to include('complexity-bar')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1011,6 +1011,31 @@ describe Users::DossiersController, type: :controller do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "#papertrail" do
|
||||||
|
before { sign_in(user) }
|
||||||
|
|
||||||
|
subject do
|
||||||
|
get :papertrail, format: :pdf, params: { id: dossier.id }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the dossier has been submitted' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, user: user) }
|
||||||
|
|
||||||
|
it 'renders a PDF document' do
|
||||||
|
subject
|
||||||
|
expect(response).to render_template(:papertrail)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when the dossier is still a draft' do
|
||||||
|
let(:dossier) { create(:dossier, :brouillon, user: user) }
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { subject }.to raise_error(ActionController::BadRequest)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#delete_dossier' do
|
describe '#delete_dossier' do
|
||||||
before { sign_in(user) }
|
before { sign_in(user) }
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,31 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
it { expect(data[:dossier][:champs][1][:__typename]).to eq "AddressChamp" }
|
it { expect(data[:dossier][:champs][1][:__typename]).to eq "AddressChamp" }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'dossier with user' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction) }
|
||||||
|
let(:query) { DOSSIER_WITH_USAGER_QUERY }
|
||||||
|
let(:variables) { { number: dossier.id } }
|
||||||
|
|
||||||
|
it { expect(data[:dossier][:usager]).not_to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'dossier with deleted user' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction) }
|
||||||
|
let(:query) { DOSSIER_WITH_USAGER_QUERY }
|
||||||
|
let(:variables) { { number: dossier.id } }
|
||||||
|
let(:email) { dossier.user.email }
|
||||||
|
|
||||||
|
before do
|
||||||
|
dossier.update(user_id: nil, deleted_user_email_never_send: email)
|
||||||
|
end
|
||||||
|
|
||||||
|
it {
|
||||||
|
expect(data[:dossier][:usager]).not_to be_nil
|
||||||
|
expect(data[:dossier][:usager][:email]).to eq(email)
|
||||||
|
expect(data[:dossier][:usager][:id]).to eq('<deleted>')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
DOSSIER_QUERY = <<-GRAPHQL
|
DOSSIER_QUERY = <<-GRAPHQL
|
||||||
query($number: Int!) {
|
query($number: Int!) {
|
||||||
dossier(number: $number) {
|
dossier(number: $number) {
|
||||||
|
@ -65,6 +90,19 @@ RSpec.describe Types::DossierType, type: :graphql do
|
||||||
}
|
}
|
||||||
GRAPHQL
|
GRAPHQL
|
||||||
|
|
||||||
|
DOSSIER_WITH_USAGER_QUERY = <<-GRAPHQL
|
||||||
|
query($number: Int!) {
|
||||||
|
dossier(number: $number) {
|
||||||
|
id
|
||||||
|
number
|
||||||
|
usager {
|
||||||
|
id
|
||||||
|
email
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
GRAPHQL
|
||||||
|
|
||||||
DOSSIER_WITH_ATTESTATION_QUERY = <<-GRAPHQL
|
DOSSIER_WITH_ATTESTATION_QUERY = <<-GRAPHQL
|
||||||
query($number: Int!) {
|
query($number: Int!) {
|
||||||
dossier(number: $number) {
|
dossier(number: $number) {
|
||||||
|
|
|
@ -602,5 +602,25 @@ describe Champ do
|
||||||
expect(champ.reload.data).to eq data
|
expect(champ.reload.data).to eq data
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "#input_name" do
|
||||||
|
let(:champ) { create(:champ_text) }
|
||||||
|
it { expect(champ.input_name).to eq "dossier[champs_attributes][#{champ.id}]" }
|
||||||
|
|
||||||
|
context "when private" do
|
||||||
|
let(:champ) { create(:champ_text, private: true) }
|
||||||
|
it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.id}]" }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when has parent" do
|
||||||
|
let(:champ) { create(:champ_text, parent: create(:champ_text)) }
|
||||||
|
it { expect(champ.input_name).to eq "dossier[champs_attributes][#{champ.parent_id}][champs_attributes][#{champ.id}]" }
|
||||||
|
end
|
||||||
|
|
||||||
|
context "when has private parent" do
|
||||||
|
let(:champ) { create(:champ_text, private: true, parent: create(:champ_text, private: true)) }
|
||||||
|
it { expect(champ.input_name).to eq "dossier[champs_private_attributes][#{champ.parent_id}][champs_attributes][#{champ.id}]" }
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -16,6 +16,16 @@ describe 'Dossier details:' do
|
||||||
expect(page).to have_text(dossier.commentaires.last.body)
|
expect(page).to have_text(dossier.commentaires.last.body)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the deposit receipt feature is enabled' do
|
||||||
|
before { Flipper.enable(:procedure_dossier_papertrail, procedure) }
|
||||||
|
after { Flipper.disable(:procedure_dossier_papertrail, procedure) }
|
||||||
|
|
||||||
|
it 'displays a link to download a deposit receipt' do
|
||||||
|
visit dossier_path(dossier)
|
||||||
|
expect(page).to have_link("Obtenir une attestation de dépôt de dossier", href: %r{dossiers/#{dossier.id}/papertrail.pdf})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "the user can see the mean time they are expected to wait" do
|
describe "the user can see the mean time they are expected to wait" do
|
||||||
let(:other_dossier) { create(:dossier, :accepte, :with_individual, procedure: procedure, depose_at: 10.days.ago, en_instruction_at: 9.days.ago, processed_at: Time.zone.now) }
|
let(:other_dossier) { create(:dossier, :accepte, :with_individual, procedure: procedure, depose_at: 10.days.ago, en_instruction_at: 9.days.ago, processed_at: Time.zone.now) }
|
||||||
|
|
||||||
|
|
25
spec/views/users/dossiers/papertrail.pdf.prawl_spec.rb
Normal file
25
spec/views/users/dossiers/papertrail.pdf.prawl_spec.rb
Normal file
|
@ -0,0 +1,25 @@
|
||||||
|
describe 'users/dossiers/papertrail.pdf.prawn', type: :view do
|
||||||
|
before do
|
||||||
|
assign(:dossier, dossier)
|
||||||
|
end
|
||||||
|
|
||||||
|
subject { render }
|
||||||
|
|
||||||
|
context 'for a dossier with an individual' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, :with_service, :with_individual) }
|
||||||
|
|
||||||
|
it 'renders a PDF document with the dossier state' do
|
||||||
|
subject
|
||||||
|
expect(rendered).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for a dossier with a SIRET' do
|
||||||
|
let(:dossier) { create(:dossier, :en_construction, :with_service, :with_entreprise) }
|
||||||
|
|
||||||
|
it 'renders a PDF document with the dossier state' do
|
||||||
|
subject
|
||||||
|
expect(rendered).to be_present
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Add table
Reference in a new issue