Skip to content

Commit 009cc1a

Browse files
tchakclaude
andcommitted
feat(seeds): add brouillon, sva/svr and tous-champs seed cases
Extract common custom procedure builders into seeds: a plain draft procedure (procedures.brouillon), published SVA/SVR procedures (cases/sva) and a procedure carrying every type de champ with a repetition and a brouillon dossier (cases/champs, bulk-built). Migrate ~15 dossier spec sites and the type_de_champ all-types context onto them. Kept on factories after measurement: single-example files and per-example work over the 73-champ dossier, where seeding costs more than it saves. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
1 parent 2c14f7e commit 009cc1a

5 files changed

Lines changed: 184 additions & 21 deletions

File tree

db/seeds/cases/champs.rb

Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
# frozen_string_literal: true
2+
3+
# A draft procedure carrying one champ of every type (public) and one
4+
# annotation of every type (private), mirroring the factory traits
5+
# :with_all_champs / :with_all_annotations (same libelles: the type name,
6+
# except drop_down_list which is labeled simple_drop_down_list). The
7+
# repetition has two children, and a brouillon dossier is seeded with its
8+
# default champs. Load in a spec with `seed "cases/champs"`.
9+
10+
procedure = Procedure.find_by(libelle: "Démarche avec tous les types de champ")
11+
12+
if procedure.nil?
13+
ActiveRecord::Base.transaction do
14+
procedure = Procedure.new(
15+
libelle: "Démarche avec tous les types de champ",
16+
description: "Une démarche de démonstration avec un champ de chaque type.",
17+
cadre_juridique: "https://www.legifrance.gouv.fr/",
18+
duree_conservation_dossiers_dans_ds: 3,
19+
max_duree_conservation_dossiers_dans_ds: Procedure::OLD_MAX_DUREE_CONSERVATION,
20+
for_individual: true,
21+
administrateurs: [administrateurs.default]
22+
)
23+
procedure.draft_revision = procedure.revisions.build
24+
procedure.save!
25+
instructeurs.default.assign_to_procedure(procedure)
26+
27+
# .beta.gouv.fr domains must be explicitly allowed via
28+
# ALLOWED_API_DOMAINS_FROM_FRONTEND; plain .gouv.fr domains always are.
29+
referentiel_domain = ENV.fetch("ALLOWED_API_DOMAINS_FROM_FRONTEND", "").split(",").grep(/rnb-api.beta.gouv/).first || "https://rnb-api.data.gouv.fr"
30+
referentiel = Referentiels::APIReferentiel.create!(
31+
mode: "exact_match",
32+
url_tiptap: {
33+
"type" => "doc",
34+
"content" => [
35+
{
36+
"type" => "paragraph",
37+
"content" => [
38+
{ "type" => "text", "text" => "#{referentiel_domain}/api/alpha/buildings/" },
39+
{ "type" => "mention", "attrs" => { "id" => "{query}", "label" => "Valeur saisie par l'usager" } },
40+
],
41+
},
42+
],
43+
},
44+
test_data_tiptap: { "{query}" => "PG46YY6YWCX8" }
45+
)
46+
47+
extra_params_by_type = {
48+
"drop_down_list" => { libelle: "simple_drop_down_list", drop_down_options: ["val1", "val2", "val3"] },
49+
"multiple_drop_down_list" => { drop_down_options: ["val1", "val2", "val3"] },
50+
"linked_drop_down_list" => { drop_down_options: ["--primary--", "secondary"] },
51+
"referentiel" => { referentiel:, mandatory: true },
52+
}
53+
54+
# Build all coordinates in memory and save the revision once: one champ of
55+
# every type per list, faster than one add_type_de_champ call per champ.
56+
revision = procedure.draft_revision
57+
58+
build_type_de_champ = lambda do |params, private_champ, position|
59+
type_de_champ = TypeDeChamp.new(private: private_champ, libelle: params[:type_champ], **params)
60+
revision.revision_types_de_champ.build(type_de_champ:, position:)
61+
62+
if type_de_champ.type_champ == TypeDeChamp.type_champs.fetch(:piece_justificative) && type_de_champ.nature.blank?
63+
type_de_champ.piece_justificative_template.attach(
64+
io: StringIO.new("toto"),
65+
filename: "toto.txt",
66+
content_type: "text/plain",
67+
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
68+
)
69+
end
70+
end
71+
72+
[false, true].each do |private_champ|
73+
TypeDeChamp.type_champs.each_value.with_index do |type_champ, position|
74+
build_type_de_champ.call({ type_champ:, **extra_params_by_type.fetch(type_champ, {}) }, private_champ, position)
75+
end
76+
end
77+
78+
# titre_identite is a piece_justificative nature, not a type_champ
79+
build_type_de_champ.call(
80+
{ type_champ: "piece_justificative", nature: "titre_identite", libelle: "titre_identité" },
81+
false,
82+
TypeDeChamp.type_champs.size
83+
)
84+
85+
revision.save!
86+
87+
repetition_coordinate = revision.revision_types_de_champ.find { it.type_de_champ.repetition? && !it.type_de_champ.private? }
88+
[
89+
{ type_champ: "text", libelle: "sub type de champ" },
90+
{ type_champ: "integer_number", libelle: "sub type de champ2" },
91+
].each_with_index do |params, position|
92+
revision.revision_types_de_champ.create!(type_de_champ: TypeDeChamp.create!(params), parent: repetition_coordinate, position:)
93+
end
94+
end
95+
end
96+
97+
procedures.label tous_champs: procedure
98+
99+
dossier = procedure.dossiers.first
100+
101+
if dossier.nil?
102+
dossier = Dossier.create!(
103+
user: users.usager,
104+
revision: procedure.active_revision,
105+
groupe_instructeur: procedure.defaut_groupe_instructeur,
106+
individual: Individual.new(gender: "Mme", nom: "Dupont", prenom: "Jeanne", birthdate: Date.new(1985, 3, 12)),
107+
autorisation_donnees: true
108+
)
109+
dossier.build_default_values
110+
end
111+
112+
dossiers.label tous_champs: dossier

db/seeds/cases/sva.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# frozen_string_literal: true
2+
3+
# Published procedures configured for SVA / SVR decisions (silence vaut
4+
# accord / rejet). Load in a spec with `seed "cases/sva"`.
5+
6+
["sva", "svr"].each do |decision|
7+
procedure = Procedure.find_with_path("demarche-demo-#{decision}").first
8+
9+
if procedure.nil?
10+
procedure = Procedure.new(
11+
libelle: "Démarche de démonstration (#{decision.upcase})",
12+
description: "Une démarche de démonstration en décision automatique #{decision.upcase}.",
13+
cadre_juridique: "https://www.legifrance.gouv.fr/",
14+
lien_site_web: "https://www.exemple.fr",
15+
duree_conservation_dossiers_dans_ds: 3,
16+
max_duree_conservation_dossiers_dans_ds: Procedure::OLD_MAX_DUREE_CONSERVATION,
17+
for_individual: true,
18+
administrateurs: [administrateurs.default],
19+
sva_svr: SVASVRConfiguration.new(decision:).attributes
20+
)
21+
procedure.draft_revision = procedure.revisions.build
22+
procedure.save!
23+
24+
type_de_champ = procedure.draft_revision.add_type_de_champ(type_champ: "text", libelle: "Nom du projet", mandatory: true)
25+
raise type_de_champ.errors.full_messages.to_sentence if type_de_champ.errors.any?
26+
27+
procedure.publish_or_reopen!(administrateurs.default, "demarche-demo-#{decision}")
28+
instructeurs.default.assign_to_procedure(procedure)
29+
end
30+
31+
procedures.label(decision.to_sym => procedure)
32+
end

db/seeds/procedures.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,20 @@
3434
end
3535

3636
procedures.label individual: procedure
37+
38+
brouillon_procedure = Procedure.find_by(libelle: "Démarche de démonstration (brouillon)")
39+
40+
if brouillon_procedure.nil?
41+
brouillon_procedure = Procedure.new(
42+
libelle: "Démarche de démonstration (brouillon)",
43+
description: "Une démarche de démonstration encore en brouillon.",
44+
cadre_juridique: "https://www.legifrance.gouv.fr/",
45+
duree_conservation_dossiers_dans_ds: 3,
46+
max_duree_conservation_dossiers_dans_ds: Procedure::OLD_MAX_DUREE_CONSERVATION,
47+
administrateurs: [administrateurs.default]
48+
)
49+
brouillon_procedure.draft_revision = brouillon_procedure.revisions.build
50+
brouillon_procedure.save!
51+
end
52+
53+
procedures.label brouillon: brouillon_procedure

spec/models/dossier_spec.rb

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
describe Dossier, :oaken, type: :model do
44
include ActionView::Helpers::SanitizeHelper
55

6-
before_all { seed "cases/entreprise" }
6+
before_all { seed "cases/entreprise", "cases/sva" }
77

88
let(:user) { create(:user) }
99

@@ -50,7 +50,7 @@
5050
end
5151

5252
describe 'by_statut' do
53-
let_it_be(:procedure) { create(:procedure) }
53+
let_it_be(:procedure) { procedures.brouillon }
5454
let_it_be(:dossier_en_construction) { create(:dossier, :en_construction, procedure:) }
5555
let_it_be(:dossier_en_instruction) { create(:dossier, :en_instruction, procedure:) }
5656
let_it_be(:dossier_accepte) { create(:dossier, :accepte, procedure:) }
@@ -191,7 +191,7 @@
191191
end
192192

193193
describe 'validations' do
194-
let(:procedure) { create(:procedure, :for_individual) }
194+
let(:procedure) { procedures.individual }
195195
subject(:dossier) { create(:dossier, procedure: procedure) }
196196

197197
it 'validates presence of required attributes' do
@@ -942,7 +942,7 @@
942942
end
943943

944944
describe "#assign_to_groupe_instructeur" do
945-
let(:procedure) { create(:procedure) }
945+
let(:procedure) { procedures.brouillon }
946946
let(:new_groupe_instructeur_new_procedure) { create(:groupe_instructeur) }
947947
let(:new_instructeur) { create(:instructeur) }
948948
let(:new_groupe_instructeur) { create(:groupe_instructeur, procedure: procedure, instructeurs: [new_instructeur]) }
@@ -959,7 +959,7 @@
959959
end
960960

961961
context "when the groupe instructeur change" do
962-
let(:procedure) { create(:procedure) }
962+
let(:procedure) { procedures.brouillon }
963963
let(:instructeur) { create(:instructeur) }
964964
let(:new_instructeur) { create(:instructeur) }
965965
let(:previous_groupe_instructeur) { create(:groupe_instructeur, procedure:, instructeurs: [instructeur]) }
@@ -1019,7 +1019,7 @@
10191019
let(:new_groupe_instructeur) { create(:groupe_instructeur, procedure:, instructeurs: [new_instructeur]) }
10201020

10211021
context "when notification is dossier_expirant" do
1022-
let(:procedure) { create(:procedure) }
1022+
let(:procedure) { procedures.brouillon }
10231023
let(:dossier) { create(:dossier, :accepte, procedure:) }
10241024
before { dossier.update(expired_at: 1.week.from_now) }
10251025

@@ -1258,7 +1258,7 @@ def types_de_champ_private
12581258
end
12591259

12601260
describe '#owner_name' do
1261-
let(:procedure) { create(:procedure) }
1261+
let(:procedure) { procedures.brouillon }
12621262
subject { dossier.owner_name }
12631263

12641264
context 'when there is no entreprise or individual' do
@@ -1638,7 +1638,7 @@ def types_de_champ_private
16381638
end
16391639

16401640
context 'as sva procedure' do
1641-
let_it_be(:procedure) { create(:procedure, :for_individual, :published, :sva) }
1641+
let(:procedure) { procedures.sva }
16421642
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure:, sva_svr_decision_on: Date.current, en_instruction_at: DateTime.new(2021, 5, 1, 12)) }
16431643
let!(:attestation_template) { create(:attestation_template, procedure:, kind: :acceptation, state: :published) }
16441644

@@ -1661,7 +1661,7 @@ def types_de_champ_private
16611661
describe '#refuser_automatiquement' do
16621662
context 'as svr procedure' do
16631663
let(:last_operation) { dossier.dossier_operation_logs.last }
1664-
let_it_be(:procedure) { create(:procedure, :for_individual, :published, :svr) }
1664+
let(:procedure) { procedures.svr }
16651665
let(:dossier) { create(:dossier, :en_instruction, :with_individual, procedure:, sva_svr_decision_on: Date.current, en_instruction_at: DateTime.new(2021, 5, 1, 12)) }
16661666

16671667
before {
@@ -1759,7 +1759,7 @@ def types_de_champ_private
17591759
end
17601760

17611761
context "via procedure sva" do
1762-
let_it_be(:procedure) { create(:procedure, :sva, :published, :for_individual) }
1762+
let(:procedure) { procedures.sva }
17631763
let(:dossier) { create(:dossier, :en_construction, :with_individual, procedure:, sva_svr_decision_on: 10.days.from_now) }
17641764
let(:sva_svr_decision_on) { SVASVRDecisionDateCalculatorService.new(dossier, procedure).decision_date }
17651765

@@ -1795,7 +1795,7 @@ def types_de_champ_private
17951795
it { expect(dossier.can_repasser_en_construction?).to be_truthy }
17961796

17971797
context 'when procedure is sva' do
1798-
let(:dossier) { create(:dossier, :en_instruction, procedure: create(:procedure, :sva)) }
1798+
let(:dossier) { create(:dossier, :en_instruction, procedure: procedures.sva) }
17991799

18001800
it { expect(dossier.can_repasser_en_construction?).to be_falsey }
18011801
end
@@ -1882,7 +1882,7 @@ def types_de_champ_private
18821882
end
18831883

18841884
context 'when procedure has sva or svr enabled' do
1885-
let(:procedure) { create(:procedure, :published, :sva) }
1885+
let(:procedure) { procedures.sva }
18861886
let(:dossier) { create(:dossier, :en_construction, procedure:) }
18871887

18881888
it { expect(dossier.can_passer_automatiquement_en_instruction?).to be_truthy }
@@ -2498,7 +2498,7 @@ def types_de_champ_private
24982498
end
24992499

25002500
describe 'brouillon_expired and en_construction_expired' do
2501-
let(:administrateur) { administrateurs(:default_admin) }
2501+
let(:administrateur) { administrateurs.default }
25022502
let(:user) { administrateur.user }
25032503
let(:reason) { DeletedDossier.reasons.fetch(:user_request) }
25042504

@@ -2820,20 +2820,20 @@ def types_de_champ_private
28202820
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["État du dossier", "Brouillon"]) }
28212821

28222822
context 'procedure sva' do
2823-
let(:dossier) { build(:dossier, :en_instruction, procedure: create(:procedure, :sva)) }
2823+
let(:dossier) { build(:dossier, :en_instruction, procedure: procedures.sva) }
28242824

28252825
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["Date décision SVA", :sva_svr_decision_on]) }
28262826
end
28272827

28282828
context 'procedure svr' do
2829-
let(:dossier) { build(:dossier, :en_instruction, procedure: create(:procedure, :svr)) }
2829+
let(:dossier) { build(:dossier, :en_instruction, procedure: procedures.svr) }
28302830

28312831
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["Date décision SVR", :sva_svr_decision_on]) }
28322832
end
28332833
end
28342834

28352835
describe '#archivable' do
2836-
let(:procedure) { create(:procedure, :published) }
2836+
let(:procedure) { procedures.individual }
28372837

28382838
it 'includes visible termine dossiers' do
28392839
dossier = create(:dossier, :accepte, procedure:)
@@ -3013,7 +3013,7 @@ def types_de_champ_private
30133013
end
30143014

30153015
describe '#update_champs_timestamps' do
3016-
let(:procedure) { create(:procedure, types_de_champ_public: [{}, { type: :piece_justificative }, { type: :piece_justificative, nature: 'titre_identite' }]) }
3016+
let_it_be(:procedure) { create(:procedure, types_de_champ_public: [{}, { type: :piece_justificative }, { type: :piece_justificative, nature: 'titre_identite' }]) }
30173017
let(:dossier) { create(:dossier, procedure:, brouillon_close_to_expiration_notice_sent_at: 10.days.ago) }
30183018
let(:changed_champs) { dossier.champ_data.filter(&:text?) }
30193019

@@ -3100,7 +3100,7 @@ def create_archived_dossier_for_month(procedure, year, month)
31003100

31013101
describe "#skip_user_notification_email?" do
31023102
context "when the dossier is brouillon for a declarative procedure" do
3103-
let(:procedure) { create(:procedure, :published, declarative_with_state: :en_instruction) }
3103+
let(:procedure) { procedures.individual.tap { it.update!(declarative_with_state: :en_instruction) } }
31043104
let(:dossier) { create(:dossier, :brouillon, procedure:) }
31053105

31063106
it "allows the email to be sent (bug fix 06/2026)" do

spec/models/type_de_champ_spec.rb

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@
22

33
describe TypeDeChamp do
44
describe 'validation' do
5-
context 'type' do
5+
context 'type', :oaken do
6+
before_all { seed "cases/champs" }
7+
68
it do
79
is_expected.not_to allow_value(nil).for(:type_champ)
810
is_expected.not_to allow_value('').for(:type_champ)
911
end
1012

11-
let(:procedure) { create(:procedure, :with_all_champs) }
12-
let(:dossier) { create(:dossier, procedure:) }
13+
let(:procedure) { procedures.tous_champs }
14+
let(:dossier) { dossiers.tous_champs }
1315

1416
it do
1517
dossier.revision.root_types_de_champ_public.each do |type_de_champ|

0 commit comments

Comments
 (0)