Merge pull request #9077 from tchak/fix-revisions-task
task(revision): find and correct all champs with wrong type de champ
This commit is contained in:
commit
d188f0fc33
3 changed files with 156 additions and 0 deletions
69
app/lib/recovery/align_champ_with_dossier_revision.rb
Normal file
69
app/lib/recovery/align_champ_with_dossier_revision.rb
Normal file
|
@ -0,0 +1,69 @@
|
|||
class Recovery::AlignChampWithDossierRevision
|
||||
def initialize(dossiers, progress: nil)
|
||||
@dossiers = dossiers
|
||||
@progress = progress
|
||||
@logs = []
|
||||
end
|
||||
|
||||
attr_reader :logs
|
||||
|
||||
def run(destroy_extra_champs: false)
|
||||
@logs = []
|
||||
bad_dossier_ids = find_broken_dossier_ids
|
||||
|
||||
Dossier
|
||||
.where(id: bad_dossier_ids)
|
||||
.includes(:procedure, champs: { type_de_champ: :revisions })
|
||||
.find_each do |dossier|
|
||||
bad_champs = dossier.champs.filter { !dossier.revision_id.in?(_1.type_de_champ.revisions.ids) }
|
||||
bad_champs.each do |champ|
|
||||
type_de_champ = dossier.revision.types_de_champ.find { _1.stable_id == champ.stable_id }
|
||||
state = {
|
||||
champ_id: champ.id,
|
||||
champ_type_de_champ_id: champ.type_de_champ_id,
|
||||
dossier_id: dossier.id,
|
||||
dossier_revision_id: dossier.revision_id,
|
||||
procedure_id: dossier.procedure.id
|
||||
}
|
||||
if type_de_champ.present?
|
||||
logs << state.merge(status: :updated, type_de_champ_id: type_de_champ.id)
|
||||
champ.update_column(:type_de_champ_id, type_de_champ.id)
|
||||
else
|
||||
logs << state.merge(status: :not_found)
|
||||
champ.destroy! if destroy_extra_champs
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def find_broken_dossier_ids
|
||||
bad_dossier_ids = []
|
||||
|
||||
@dossiers.in_batches(of: 15_000) do |dossiers|
|
||||
dossier_ids_revision_ids = dossiers.pluck(:id, :revision_id)
|
||||
dossier_ids = dossier_ids_revision_ids.map(&:first)
|
||||
dossier_ids_type_de_champ_ids = Champ.where(dossier_id: dossier_ids).pluck(:dossier_id, :type_de_champ_id)
|
||||
type_de_champ_ids = dossier_ids_type_de_champ_ids.map(&:second).uniq
|
||||
revision_ids_by_type_de_champ_id = ProcedureRevisionTypeDeChamp
|
||||
.where(type_de_champ_id: type_de_champ_ids)
|
||||
.pluck(:type_de_champ_id, :revision_id)
|
||||
.group_by(&:first).transform_values { _1.map(&:second).uniq }
|
||||
|
||||
type_de_champ_ids_by_dossier_id = dossier_ids_type_de_champ_ids
|
||||
.group_by(&:first)
|
||||
.transform_values { _1.map(&:second).uniq }
|
||||
|
||||
bad_dossier_ids += dossier_ids_revision_ids.filter do |(dossier_id, revision_id)|
|
||||
type_de_champ_ids_by_dossier_id.fetch(dossier_id, []).any? do |type_de_champ_id|
|
||||
!revision_id.in?(revision_ids_by_type_de_champ_id.fetch(type_de_champ_id, []))
|
||||
end
|
||||
end.map(&:first)
|
||||
|
||||
@progress.inc(dossiers.count) if @progress
|
||||
end
|
||||
|
||||
@progress.finish if @progress
|
||||
|
||||
bad_dossier_ids
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
namespace :after_party do
|
||||
desc 'Deployment task: fix_champs_revisions'
|
||||
task fix_champs_revisions: :environment do
|
||||
puts "Running deploy task 'fix_champs_revisions'"
|
||||
|
||||
progress = ProgressReport.new(Dossier.count)
|
||||
|
||||
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier, progress:)
|
||||
fixer.run
|
||||
fixer.logs.each do |log|
|
||||
puts JSON.dump(log)
|
||||
end
|
||||
|
||||
# Update task as completed. If you remove the line below, the task will
|
||||
# run with every deploy (or every time you call after_party:run).
|
||||
AfterParty::TaskRecord
|
||||
.create version: AfterParty::TaskRecorder.new(__FILE__).timestamp
|
||||
end
|
||||
end
|
68
spec/lib/recovery/align_champ_with_dossier_revision_spec.rb
Normal file
68
spec/lib/recovery/align_champ_with_dossier_revision_spec.rb
Normal file
|
@ -0,0 +1,68 @@
|
|||
describe Recovery::AlignChampWithDossierRevision do
|
||||
let(:procedure) { create(:procedure, types_de_champ_public: [{ stable_id: bad_stable_id }, {}]) }
|
||||
let(:dossier) { create(:dossier, :with_populated_champs, procedure:) }
|
||||
let(:bad_dossier) { create(:dossier, :with_populated_champs, procedure:) }
|
||||
let(:bad_stable_id) { 999 }
|
||||
let(:bad_champ) { bad_dossier.champs.find { bad_stable_id == _1.stable_id } }
|
||||
|
||||
context 'when type_de_champ exists in dossier revision' do
|
||||
before do
|
||||
procedure.publish!
|
||||
procedure.draft_revision
|
||||
.find_and_ensure_exclusive_use(bad_stable_id)
|
||||
.update(libelle: "New libelle")
|
||||
previous_revision = procedure.published_revision
|
||||
previous_type_de_champ = previous_revision.types_de_champ.find { bad_stable_id == _1.stable_id }
|
||||
|
||||
procedure.publish_revision!
|
||||
procedure.reload
|
||||
|
||||
bad_dossier
|
||||
bad_champ.update(type_de_champ: previous_type_de_champ)
|
||||
end
|
||||
|
||||
it 'bad dossier shoud be bad' do
|
||||
expect(procedure.revisions.size).to eq(3)
|
||||
expect(bad_dossier.revision).to eq(procedure.published_revision)
|
||||
expect(bad_dossier.champs.size).to eq(2)
|
||||
expect(bad_dossier.champs_public.size).to eq(1)
|
||||
expect { DossierPreloader.load_one(bad_dossier) }.to raise_error(ArgumentError)
|
||||
|
||||
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
|
||||
fixer.run
|
||||
|
||||
expect(fixer.logs.size).to eq(1)
|
||||
expect(fixer.logs.first.fetch(:status)).to eq(:updated)
|
||||
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error(ArgumentError)
|
||||
expect(bad_dossier.champs.size).to eq(2)
|
||||
expect(bad_dossier.champs_public.size).to eq(2)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when type_de_champ does not exist in dossier revision' do
|
||||
before do
|
||||
procedure.publish!
|
||||
bad_dossier
|
||||
procedure.draft_revision.remove_type_de_champ(bad_stable_id)
|
||||
procedure.publish_revision!
|
||||
bad_dossier.update(revision: procedure.published_revision)
|
||||
end
|
||||
|
||||
it 'bad dossier shoud be bad' do
|
||||
expect(procedure.revisions.size).to eq(3)
|
||||
expect(bad_dossier.revision).to eq(procedure.published_revision)
|
||||
expect(bad_dossier.champs.size).to eq(2)
|
||||
expect(bad_dossier.champs_public.size).to eq(2)
|
||||
expect { DossierPreloader.load_one(bad_dossier) }.to raise_error(ArgumentError)
|
||||
|
||||
fixer = Recovery::AlignChampWithDossierRevision.new(Dossier)
|
||||
fixer.run(destroy_extra_champs: true)
|
||||
|
||||
expect(fixer.logs.size).to eq(1)
|
||||
expect(fixer.logs.first.fetch(:status)).to eq(:not_found)
|
||||
expect { DossierPreloader.load_one(bad_dossier) }.not_to raise_error(ArgumentError)
|
||||
expect(bad_dossier.champs.size).to eq(1)
|
||||
expect(bad_dossier.champs_public.size).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue