diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql
index 4a719effe..a81e39392 100644
--- a/app/graphql/schema.graphql
+++ b/app/graphql/schema.graphql
@@ -1291,6 +1291,11 @@ enum TypeDeChamp {
"""
textarea
+ """
+ Titre identité
+ """
+ titre_identite
+
"""
Oui/Non
"""
diff --git a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js
index 57131402b..98ad6af76 100644
--- a/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js
+++ b/app/javascript/components/TypesDeChampEditor/components/TypeDeChamp.js
@@ -26,6 +26,7 @@ const TypeDeChamp = sortableElement(
const isCarte = typeDeChamp.type_champ === 'carte';
const isExplication = typeDeChamp.type_champ === 'explication';
const isHeaderSection = typeDeChamp.type_champ === 'header_section';
+ const isTitreIdentite = typeDeChamp.type_champ === 'titre_identite';
const isRepetition = typeDeChamp.type_champ === 'repetition';
const canBeMandatory =
!isHeaderSection && !isExplication && !state.isAnnotation;
@@ -118,7 +119,7 @@ const TypeDeChamp = sortableElement(
diff --git a/app/models/champs/titre_identite_champ.rb b/app/models/champs/titre_identite_champ.rb
new file mode 100644
index 000000000..460960ed5
--- /dev/null
+++ b/app/models/champs/titre_identite_champ.rb
@@ -0,0 +1,57 @@
+# == Schema Information
+#
+# Table name: champs
+#
+# id :integer not null, primary key
+# private :boolean default(FALSE), not null
+# row :integer
+# type :string
+# value :string
+# created_at :datetime
+# updated_at :datetime
+# dossier_id :integer
+# etablissement_id :integer
+# parent_id :bigint
+# type_de_champ_id :integer
+#
+class Champs::TitreIdentiteChamp < Champ
+ MAX_SIZE = 20.megabytes
+
+ ACCEPTED_FORMATS = [
+ "image/png",
+ "image/jpeg"
+ ]
+
+ # TODO: once we're running on Rails 6, re-enable this validation.
+ # See https://github.com/betagouv/demarches-simplifiees.fr/issues/4926
+ #
+ validates :piece_justificative_file,
+ content_type: ACCEPTED_FORMATS,
+ size: { less_than: MAX_SIZE }
+
+ def main_value_name
+ :piece_justificative_file
+ end
+
+ def search_terms
+ # We don’t know how to search inside documents yet
+ end
+
+ def mandatory_and_blank?
+ mandatory? && !piece_justificative_file.attached?
+ end
+
+ def for_export
+ piece_justificative_file.filename.to_s if piece_justificative_file.attached?
+ end
+
+ def for_api
+ if piece_justificative_file.attached? && (piece_justificative_file.virus_scanner.safe? || piece_justificative_file.virus_scanner.pending?)
+ piece_justificative_file.service_url
+ end
+ end
+
+ def update_skip_pj_validation
+ type_de_champ.update(skip_pj_validation: true)
+ end
+end
diff --git a/app/models/type_de_champ.rb b/app/models/type_de_champ.rb
index 02c3425f0..9974ef1f2 100644
--- a/app/models/type_de_champ.rb
+++ b/app/models/type_de_champ.rb
@@ -47,7 +47,8 @@ class TypeDeChamp < ApplicationRecord
piece_justificative: 'piece_justificative',
siret: 'siret',
carte: 'carte',
- repetition: 'repetition'
+ repetition: 'repetition',
+ titre_identite: 'titre_identite'
}
belongs_to :revision, class_name: 'ProcedureRevision', optional: true
@@ -189,7 +190,7 @@ class TypeDeChamp < ApplicationRecord
end
def piece_justificative?
- type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative)
+ type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) || type_champ == TypeDeChamp.type_champs.fetch(:titre_identite)
end
def legacy_number?
diff --git a/app/models/types_de_champ/titre_identite_type_de_champ.rb b/app/models/types_de_champ/titre_identite_type_de_champ.rb
new file mode 100644
index 000000000..7118fed08
--- /dev/null
+++ b/app/models/types_de_champ/titre_identite_type_de_champ.rb
@@ -0,0 +1,2 @@
+class TypesDeChamp::TitreIdentiteTypeDeChamp < TypesDeChamp::TypeDeChampBase
+end
diff --git a/app/views/shared/dossiers/_champ_row.html.haml b/app/views/shared/dossiers/_champ_row.html.haml
index 18d69d390..6d6461468 100644
--- a/app/views/shared/dossiers/_champ_row.html.haml
+++ b/app/views/shared/dossiers/_champ_row.html.haml
@@ -26,6 +26,8 @@
= render partial: "shared/champs/multiple_drop_down_list/show", locals: { champ: c }
- when TypeDeChamp.type_champs.fetch(:piece_justificative)
= render partial: "shared/champs/piece_justificative/show", locals: { champ: c }
+ - when TypeDeChamp.type_champs.fetch(:titre_identite)
+ = render partial: "shared/champs/piece_justificative/show", locals: { champ: c }
- when TypeDeChamp.type_champs.fetch(:siret)
= render partial: "shared/champs/siret/show", locals: { champ: c, profile: profile }
- when TypeDeChamp.type_champs.fetch(:textarea)
diff --git a/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml b/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml
index a446bf5f7..0331de761 100644
--- a/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml
+++ b/app/views/shared/dossiers/editable_champs/_editable_champ.html.haml
@@ -6,6 +6,8 @@
- elsif has_label?(champ)
= render partial: 'shared/dossiers/editable_champs/champ_label', locals: { form: form, champ: champ, seen_at: defined?(seen_at) ? seen_at : nil }
+ - if champ.type_champ == "titre_identite"
+ %p.notice Carte d'identité (uniquement le recto), passeport ou titre de séjour. Formats acceptés : jpg / png.
= render partial: "shared/dossiers/editable_champs/#{champ.type_champ}",
locals: { champ: champ, form: form }
diff --git a/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml b/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml
new file mode 100644
index 000000000..0fc1f99c8
--- /dev/null
+++ b/app/views/shared/dossiers/editable_champs/_titre_identite.html.haml
@@ -0,0 +1,4 @@
+= render 'shared/attachment/edit',
+ { form: form,
+ attached_file: champ.piece_justificative_file,
+ template: champ.type_de_champ.piece_justificative_template, user_can_destroy: true }
diff --git a/config/locales/models/type_de_champ/fr.yml b/config/locales/models/type_de_champ/fr.yml
index 924c14e54..bdc1513ac 100644
--- a/config/locales/models/type_de_champ/fr.yml
+++ b/config/locales/models/type_de_champ/fr.yml
@@ -33,3 +33,4 @@ fr:
siret: 'SIRET'
carte: 'Carte'
repetition: 'Bloc répétable'
+ titre_identite: 'Titre identité'
diff --git a/spec/factories/champ.rb b/spec/factories/champ.rb
index 7d057c320..000924b78 100644
--- a/spec/factories/champ.rb
+++ b/spec/factories/champ.rb
@@ -143,6 +143,14 @@ FactoryBot.define do
end
end
+ factory :champ_titre_identite, class: 'Champs::TitreIdentiteChamp' do
+ type_de_champ { association :type_de_champ_titre_identite, procedure: dossier.procedure }
+
+ after(:build) do |champ, _evaluator|
+ champ.piece_justificative_file.attach(io: StringIO.new("toto"), filename: "toto.png", content_type: "image/png")
+ end
+ end
+
factory :champ_carte, class: 'Champs::CarteChamp' do
type_de_champ { association :type_de_champ_carte, procedure: dossier.procedure }
end
diff --git a/spec/factories/type_de_champ.rb b/spec/factories/type_de_champ.rb
index 0c4f2b7cc..eb43d56ff 100644
--- a/spec/factories/type_de_champ.rb
+++ b/spec/factories/type_de_champ.rb
@@ -133,6 +133,9 @@ FactoryBot.define do
type_de_champ.piece_justificative_template.attach(io: StringIO.new("toto"), filename: "toto.txt", content_type: "text/plain")
end
end
+ factory :type_de_champ_titre_identite do
+ type_champ { TypeDeChamp.type_champs.fetch(:titre_identite) }
+ end
factory :type_de_champ_siret do
type_champ { TypeDeChamp.type_champs.fetch(:siret) }
end
diff --git a/spec/services/procedure_export_service_spec.rb b/spec/services/procedure_export_service_spec.rb
index 7f2945981..0f8cafdfe 100644
--- a/spec/services/procedure_export_service_spec.rb
+++ b/spec/services/procedure_export_service_spec.rb
@@ -73,6 +73,7 @@ describe ProcedureExportService do
"piece_justificative",
"siret",
"carte",
+ "titre_identite",
"text"
]
end
@@ -156,6 +157,7 @@ describe ProcedureExportService do
"piece_justificative",
"siret",
"carte",
+ "titre_identite",
"text"
]
end
@@ -235,6 +237,7 @@ describe ProcedureExportService do
"piece_justificative",
"siret",
"carte",
+ "titre_identite",
"text"
]
end