amelioration(dossier.clone): dossier.clone, permet de cloner un dossier
This commit is contained in:
parent
f1e8852fbe
commit
844004818a
12 changed files with 273 additions and 5 deletions
|
@ -215,6 +215,27 @@ class Champ < ApplicationRecord
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone(dossier:, parent: nil)
|
||||||
|
kopy = deep_clone(only: [:data, :private, :row, :type, :value, :value_json, :external_id, :type_de_champ_id])
|
||||||
|
|
||||||
|
kopy.dossier = dossier
|
||||||
|
kopy.parent = parent if parent
|
||||||
|
kopy
|
||||||
|
end
|
||||||
|
|
||||||
|
def clone_piece_justificative(kopy)
|
||||||
|
if piece_justificative_file.attached?
|
||||||
|
piece_justificative_file.open do |tempfile|
|
||||||
|
kopy.piece_justificative_file.attach({
|
||||||
|
io: File.open(tempfile.path),
|
||||||
|
filename: piece_justificative_file.filename,
|
||||||
|
content_type: piece_justificative_file.content_type,
|
||||||
|
metadata: { virus_scan_result: ActiveStorage::VirusScanner::SAFE }
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def champs_for_condition
|
def champs_for_condition
|
||||||
|
|
|
@ -115,6 +115,13 @@ class Champs::CarteChamp < Champ
|
||||||
geo_areas.blank?
|
geo_areas.blank?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone(dossier:, parent: nil)
|
||||||
|
kopy = super(dossier: dossier, parent: parent)
|
||||||
|
|
||||||
|
kopy.geo_areas = geo_areas.map(&:dup)
|
||||||
|
kopy
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def selection_utilisateur_legacy_geometry
|
def selection_utilisateur_legacy_geometry
|
||||||
|
|
|
@ -51,4 +51,11 @@ class Champs::PieceJustificativeChamp < Champ
|
||||||
piece_justificative_file.service_url
|
piece_justificative_file.service_url
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone(dossier:, parent: nil)
|
||||||
|
kopy = super(dossier: dossier, parent: parent)
|
||||||
|
|
||||||
|
clone_piece_justificative(kopy)
|
||||||
|
kopy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -77,4 +77,13 @@ class Champs::RepetitionChamp < Champ
|
||||||
] + Dossier.champs_for_export(champs, types_de_champ)
|
] + Dossier.champs_for_export(champs, types_de_champ)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone(dossier:, parent: nil)
|
||||||
|
kopy = super(dossier: dossier, parent: parent)
|
||||||
|
|
||||||
|
kopy.champs = champs.map do |champ_de_repetition|
|
||||||
|
champ_de_repetition.clone(dossier: dossier, parent: kopy)
|
||||||
|
end
|
||||||
|
kopy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -27,4 +27,11 @@ class Champs::SiretChamp < Champ
|
||||||
def mandatory_blank?
|
def mandatory_blank?
|
||||||
mandatory? && Siret.new(siret: value).invalid?
|
mandatory? && Siret.new(siret: value).invalid?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone(dossier:, parent: nil)
|
||||||
|
kopy = super(dossier: dossier, parent: parent)
|
||||||
|
|
||||||
|
kopy.etablissement = etablissement.dup
|
||||||
|
kopy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -43,4 +43,11 @@ class Champs::TitreIdentiteChamp < Champ
|
||||||
def for_api
|
def for_api
|
||||||
nil
|
nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone(dossier:, parent: nil)
|
||||||
|
kopy = super(dossier: dossier, parent: parent)
|
||||||
|
|
||||||
|
clone_piece_justificative(kopy)
|
||||||
|
kopy
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
# updated_at :datetime
|
# updated_at :datetime
|
||||||
# dossier_transfer_id :bigint
|
# dossier_transfer_id :bigint
|
||||||
# groupe_instructeur_id :bigint
|
# groupe_instructeur_id :bigint
|
||||||
|
# parent_dossier_id :bigint
|
||||||
# revision_id :bigint
|
# revision_id :bigint
|
||||||
# user_id :integer
|
# user_id :integer
|
||||||
#
|
#
|
||||||
|
@ -413,7 +414,7 @@ class Dossier < ApplicationRecord
|
||||||
delegate :siret, :siren, to: :etablissement, allow_nil: true
|
delegate :siret, :siren, to: :etablissement, allow_nil: true
|
||||||
delegate :france_connect_information, to: :user, allow_nil: true
|
delegate :france_connect_information, to: :user, allow_nil: true
|
||||||
|
|
||||||
before_save :build_default_champs, if: Proc.new { revision_id_was.nil? }
|
before_save :build_default_champs_for_new_dossier, if: Proc.new { revision_id_was.nil? && parent_dossier_id.nil? }
|
||||||
before_save :update_search_terms
|
before_save :update_search_terms
|
||||||
|
|
||||||
after_save :send_web_hook
|
after_save :send_web_hook
|
||||||
|
@ -473,8 +474,8 @@ class Dossier < ApplicationRecord
|
||||||
self.private_search_terms = champs_private.flat_map(&:search_terms).compact.join(' ')
|
self.private_search_terms = champs_private.flat_map(&:search_terms).compact.join(' ')
|
||||||
end
|
end
|
||||||
|
|
||||||
def build_default_champs
|
def build_default_champs_for_new_dossier
|
||||||
revision.build_champs_public.each do |champ|
|
revision.build_champs.each do |champ|
|
||||||
champs_public << champ
|
champs_public << champ
|
||||||
end
|
end
|
||||||
revision.build_champs_private.each do |champ|
|
revision.build_champs_private.each do |champ|
|
||||||
|
@ -1178,6 +1179,23 @@ class Dossier < ApplicationRecord
|
||||||
@sections[champ.parent || (champ.public? ? :public : :private)]
|
@sections[champ.parent || (champ.public? ? :public : :private)]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def clone
|
||||||
|
cloned_dossier = deep_clone(only: [:autorisation_donnees, :user_id, :revision_id, :groupe_instructeur_id],
|
||||||
|
include: [:individual, :etablissement]) do |original, kopy|
|
||||||
|
if original.is_a?(Dossier)
|
||||||
|
kopy.parent_dossier_id = original.id
|
||||||
|
kopy.state = Dossier.states.fetch(:brouillon)
|
||||||
|
kopy.champs = original.champs.map { |champ| champ.clone(dossier: kopy) }
|
||||||
|
kopy.champs_private = kopy.revision.types_de_champ_private.map { |tdc| tdc.build_champ(revision: kopy.revision, dossier: kopy) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
transaction do
|
||||||
|
cloned_dossier.save!
|
||||||
|
end
|
||||||
|
cloned_dossier
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def create_missing_traitemets
|
def create_missing_traitemets
|
||||||
|
|
|
@ -0,0 +1,5 @@
|
||||||
|
class AddParentDossierIdToDossier < ActiveRecord::Migration[6.1]
|
||||||
|
def change
|
||||||
|
add_column :dossiers, :parent_dossier_id, :bigint
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,8 +10,8 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2022_11_04_071959) do
|
|
||||||
|
|
||||||
|
ActiveRecord::Schema.define(version: 2022_11_07_163131) do
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "pgcrypto"
|
enable_extension "pgcrypto"
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -327,7 +327,8 @@ ActiveRecord::Schema.define(version: 2022_11_04_071959) do
|
||||||
t.datetime "last_champ_updated_at"
|
t.datetime "last_champ_updated_at"
|
||||||
t.datetime "last_commentaire_updated_at"
|
t.datetime "last_commentaire_updated_at"
|
||||||
t.text "motivation"
|
t.text "motivation"
|
||||||
t.text "private_search_terms"
|
t.bigint "parent_dossier_id"
|
||||||
|
t.string "private_search_terms"
|
||||||
t.datetime "processed_at"
|
t.datetime "processed_at"
|
||||||
t.bigint "revision_id"
|
t.bigint "revision_id"
|
||||||
t.text "search_terms"
|
t.text "search_terms"
|
||||||
|
|
|
@ -103,6 +103,18 @@ FactoryBot.define do
|
||||||
commentaires { [build(:commentaire), build(:commentaire)] }
|
commentaires { [build(:commentaire), build(:commentaire)] }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
trait :with_invites do
|
||||||
|
invites { [build(:invite)] }
|
||||||
|
end
|
||||||
|
|
||||||
|
trait :with_avis do
|
||||||
|
avis { [build(:avis)] }
|
||||||
|
end
|
||||||
|
|
||||||
|
trait :with_dossier_operation_logs do
|
||||||
|
dossier_operation_logs { [build(:dossier_operation_log)] }
|
||||||
|
end
|
||||||
|
|
||||||
trait :followed do
|
trait :followed do
|
||||||
after(:create) do |dossier, _evaluator|
|
after(:create) do |dossier, _evaluator|
|
||||||
g = create(:instructeur)
|
g = create(:instructeur)
|
||||||
|
|
|
@ -279,6 +279,11 @@ FactoryBot.define do
|
||||||
build(:type_de_champ_explication, procedure: procedure)
|
build(:type_de_champ_explication, procedure: procedure)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
trait :with_carte do
|
||||||
|
after(:build) do |procedure, _evaluator|
|
||||||
|
build(:type_de_champ_carte, procedure: procedure)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
trait :published do
|
trait :published do
|
||||||
aasm_state { :publiee }
|
aasm_state { :publiee }
|
||||||
|
|
|
@ -1685,6 +1685,175 @@ describe Dossier do
|
||||||
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["État du dossier", "Brouillon"]) }
|
it { expect(dossier.spreadsheet_columns(types_de_champ: [])).to include(["État du dossier", "Brouillon"]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#clone' do
|
||||||
|
let(:procedure) { create(:procedure, :with_type_de_champ, :with_type_de_champ_private) }
|
||||||
|
let(:dossier) { create(:dossier, procedure: procedure) }
|
||||||
|
let(:new_dossier) { dossier.clone }
|
||||||
|
|
||||||
|
context 'reset most attributes' do
|
||||||
|
it { expect(new_dossier.id).not_to eq(dossier.id) }
|
||||||
|
it { expect(new_dossier.api_entreprise_job_exceptions).to be_nil }
|
||||||
|
it { expect(new_dossier.archived).to be_falsey }
|
||||||
|
it { expect(new_dossier.brouillon_close_to_expiration_notice_sent_at).to be_nil }
|
||||||
|
it { expect(new_dossier.conservation_extension).to eq(0.seconds) }
|
||||||
|
it { expect(new_dossier.declarative_triggered_at).to be_nil }
|
||||||
|
it { expect(new_dossier.deleted_user_email_never_send).to be_nil }
|
||||||
|
it { expect(new_dossier.depose_at).to be_nil }
|
||||||
|
it { expect(new_dossier.en_construction_at).to be_nil }
|
||||||
|
it { expect(new_dossier.en_construction_close_to_expiration_notice_sent_at).to be_nil }
|
||||||
|
it { expect(new_dossier.en_instruction_at).to be_nil }
|
||||||
|
it { expect(new_dossier.for_procedure_preview).to be_falsey }
|
||||||
|
it { expect(new_dossier.groupe_instructeur_updated_at).to be_nil }
|
||||||
|
it { expect(new_dossier.hidden_at).to be_nil }
|
||||||
|
it { expect(new_dossier.hidden_by_administration_at).to be_nil }
|
||||||
|
it { expect(new_dossier.hidden_by_reason).to be_nil }
|
||||||
|
it { expect(new_dossier.hidden_by_user_at).to be_nil }
|
||||||
|
it { expect(new_dossier.identity_updated_at).to be_nil }
|
||||||
|
it { expect(new_dossier.last_avis_updated_at).to be_nil }
|
||||||
|
it { expect(new_dossier.last_champ_private_updated_at).to be_nil }
|
||||||
|
it { expect(new_dossier.last_champ_updated_at).to be_nil }
|
||||||
|
it { expect(new_dossier.last_commentaire_updated_at).to be_nil }
|
||||||
|
it { expect(new_dossier.motivation).to be_nil }
|
||||||
|
it { expect(new_dossier.private_search_terms).to eq("") }
|
||||||
|
it { expect(new_dossier.processed_at).to be_nil }
|
||||||
|
it { expect(new_dossier.search_terms).to match(dossier.user.email) }
|
||||||
|
it { expect(new_dossier.termine_close_to_expiration_notice_sent_at).to be_nil }
|
||||||
|
it { expect(new_dossier.dossier_transfer_id).to be_nil }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'copies some attributes' do
|
||||||
|
it { expect(new_dossier.groupe_instructeur).to eq(dossier.groupe_instructeur) }
|
||||||
|
it { expect(new_dossier.autorisation_donnees).to eq(dossier.autorisation_donnees) }
|
||||||
|
it { expect(new_dossier.revision_id).to eq(dossier.revision_id) }
|
||||||
|
it { expect(new_dossier.user_id).to eq(dossier.user_id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'forces some attributes' do
|
||||||
|
let(:dossier) { create(:dossier, :accepte) }
|
||||||
|
|
||||||
|
it { expect(new_dossier.brouillon?).to eq(true) }
|
||||||
|
it { expect(new_dossier.parent_dossier_id).to eq(dossier.id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'links type_de_champ' do
|
||||||
|
it { expect(new_dossier.types_de_champ.count).to eq(1) }
|
||||||
|
it { expect(new_dossier.types_de_champ).to eq(dossier.types_de_champ) }
|
||||||
|
it { expect(new_dossier.types_de_champ_private.count).to eq(1) }
|
||||||
|
it { expect(new_dossier.types_de_champ_private).to eq(dossier.types_de_champ_private) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'procedure with_individual' do
|
||||||
|
let(:procedure) { create(:procedure, :for_individual) }
|
||||||
|
it { expect(new_dossier.individual.slice(:nom, :prenom, :gender)).to eq(dossier.individual.slice(:nom, :prenom, :gender)) }
|
||||||
|
it { expect(new_dossier.individual.id).not_to eq(dossier.individual.id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'procedure with etablissement' do
|
||||||
|
let(:dossier) { create(:dossier, :with_entreprise) }
|
||||||
|
it { expect(new_dossier.etablissement.slice(:siret)).to eq(dossier.etablissement.slice(:siret)) }
|
||||||
|
it { expect(new_dossier.etablissement.id).not_to eq(dossier.etablissement.id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'skips commentaires' do
|
||||||
|
let(:dossier) { create(:dossier, :with_commentaires) }
|
||||||
|
|
||||||
|
it { expect(new_dossier.commentaires.count).not_to eq(dossier.commentaires.count) }
|
||||||
|
it { expect(new_dossier.commentaires.size).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'skips invites' do
|
||||||
|
let(:dossier) { create(:dossier, :with_invites) }
|
||||||
|
|
||||||
|
it { expect(new_dossier.invites.count).not_to eq(dossier.invites.count) }
|
||||||
|
it { expect(new_dossier.invites.count).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'skips avis' do
|
||||||
|
let(:dossier) { create(:dossier, :with_avis) }
|
||||||
|
|
||||||
|
it { expect(new_dossier.avis.count).not_to eq(dossier.avis.count) }
|
||||||
|
it { expect(new_dossier.avis.count).to eq(0) }
|
||||||
|
it { expect(new_dossier.experts.count).not_to eq(dossier.experts.count) }
|
||||||
|
it { expect(new_dossier.experts.count).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'skips dossier_operation_logs' do
|
||||||
|
let(:dossier) { create(:dossier, :accepte, :with_dossier_operation_logs) }
|
||||||
|
|
||||||
|
it { expect(new_dossier.dossier_operation_logs.count).not_to eq(dossier.dossier_operation_logs.count) }
|
||||||
|
it { expect(new_dossier.dossier_operation_logs.count).to eq(0) }
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'champs' do
|
||||||
|
it { expect(new_dossier.id).not_to eq(dossier.id) }
|
||||||
|
|
||||||
|
context 'public are duplicated' do
|
||||||
|
it { expect(new_dossier.champs.count).to eq(dossier.champs.count) }
|
||||||
|
it { expect(new_dossier.champs.ids).not_to eq(dossier.champs.ids) }
|
||||||
|
|
||||||
|
it 'keeps champs.values' do
|
||||||
|
original_first_champ = dossier.champs.first
|
||||||
|
original_first_champ.update!(value: 'kthxbye')
|
||||||
|
|
||||||
|
expect(new_dossier.champs.first.value).to eq(original_first_champ.value)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Champs::Repetition with rows, original_champ.repetition and rows are duped' do
|
||||||
|
let(:dossier) { create(:dossier) }
|
||||||
|
let(:type_de_champ_repetition) { create(:type_de_champ_repetition, procedure: dossier.procedure) }
|
||||||
|
let(:champ_repetition) { create(:champ_repetition, type_de_champ: type_de_champ_repetition, dossier: dossier) }
|
||||||
|
before { dossier.champs << champ_repetition }
|
||||||
|
|
||||||
|
it { expect(Champs::RepetitionChamp.where(dossier: new_dossier).first.champs.count).to eq(4) }
|
||||||
|
it { expect(Champs::RepetitionChamp.where(dossier: new_dossier).first.champs.ids).not_to eq(champ_repetition.champs.ids) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Champs::CarteChamp with geo areas, original_champ.geo_areas are duped' do
|
||||||
|
let(:dossier) { create(:dossier) }
|
||||||
|
let(:type_de_champ_carte) { create(:type_de_champ_carte, procedure: dossier.procedure) }
|
||||||
|
let(:geo_area) { create(:geo_area, :selection_utilisateur, :polygon) }
|
||||||
|
let(:champ_carte) { create(:champ_carte, type_de_champ: type_de_champ_carte, geo_areas: [geo_area]) }
|
||||||
|
before { dossier.champs << champ_carte }
|
||||||
|
|
||||||
|
it { expect(Champs::CarteChamp.where(dossier: new_dossier).first.geo_areas.count).to eq(1) }
|
||||||
|
it { expect(Champs::CarteChamp.where(dossier: new_dossier).first.geo_areas.ids).not_to eq(champ_carte.geo_areas.ids) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Champs::SiretChamp, original_champ.etablissement is duped' do
|
||||||
|
let(:dossier) { create(:dossier) }
|
||||||
|
let(:type_de_champs_siret) { create(:type_de_champ_siret, procedure: dossier.procedure) }
|
||||||
|
let(:etablissement) { create(:etablissement) }
|
||||||
|
let(:champ_siret) { create(:champ_siret, type_de_champ: type_de_champs_siret, etablissement: create(:etablissement)) }
|
||||||
|
before { dossier.champs << champ_siret }
|
||||||
|
|
||||||
|
it { expect(Champs::SiretChamp.where(dossier: dossier).first.etablissement).not_to be_nil }
|
||||||
|
it { expect(Champs::SiretChamp.where(dossier: new_dossier).first.etablissement.id).not_to eq(champ_siret.etablissement.id) }
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'for Champs::PieceJustificative, original_champ.piece_justificative_file is duped' do
|
||||||
|
let(:dossier) { create(:dossier) }
|
||||||
|
let(:champ_piece_justificative) { create(:champ_piece_justificative, dossier_id: dossier.id) }
|
||||||
|
before { dossier.champs << champ_piece_justificative }
|
||||||
|
it { expect(Champs::PieceJustificativeChamp.where(dossier: dossier).first.piece_justificative_file).not_to be_nil }
|
||||||
|
it { expect(Champs::PieceJustificativeChamp.where(dossier: new_dossier).first.piece_justificative_file.blob.id).not_to eq(champ_piece_justificative.piece_justificative_file.blob.id) }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'private are renewd' do
|
||||||
|
it { expect(new_dossier.champs_private.count).to eq(dossier.champs_private.count) }
|
||||||
|
it { expect(new_dossier.champs_private.ids).not_to eq(dossier.champs_private.ids) }
|
||||||
|
|
||||||
|
it 'reset champs private values' do
|
||||||
|
original_first_champs_private = dossier.champs_private.first
|
||||||
|
original_first_champs_private.update!(value: 'kthxbye')
|
||||||
|
|
||||||
|
expect(new_dossier.champs_private.first.value).not_to eq(original_first_champs_private.value)
|
||||||
|
expect(new_dossier.champs_private.first.value).to eq(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe '#processed_in_month' do
|
describe '#processed_in_month' do
|
||||||
include ActiveSupport::Testing::TimeHelpers
|
include ActiveSupport::Testing::TimeHelpers
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue