Merge pull request #8190 from tchak/feat-demarche-declarative
refactor(demarche): make declarative demarche processing syncroneous
This commit is contained in:
commit
6207e633d7
7 changed files with 42 additions and 181 deletions
|
@ -165,6 +165,7 @@ module Users
|
||||||
|
|
||||||
if errors.blank?
|
if errors.blank?
|
||||||
@dossier.passer_en_construction!
|
@dossier.passer_en_construction!
|
||||||
|
@dossier.process_declarative!
|
||||||
NotificationMailer.send_en_construction_notification(@dossier).deliver_later
|
NotificationMailer.send_en_construction_notification(@dossier).deliver_later
|
||||||
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
|
@dossier.groupe_instructeur.instructeurs.with_instant_email_dossier_notifications.each do |instructeur|
|
||||||
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
|
DossierMailer.notify_new_dossier_depose_to_instructeur(@dossier, instructeur.email).deliver_later
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
class Cron::DeclarativeProceduresJob < Cron::CronJob
|
|
||||||
self.schedule_expression = "every 1 minute"
|
|
||||||
|
|
||||||
def perform(*args)
|
|
||||||
Procedure.declarative.find_each do |procedure|
|
|
||||||
begin
|
|
||||||
procedure.process_dossiers!
|
|
||||||
rescue => e
|
|
||||||
Sentry.capture_exception(e)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -169,7 +169,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
event :passer_automatiquement_en_instruction, after: :after_passer_automatiquement_en_instruction do
|
event :passer_automatiquement_en_instruction, after: :after_passer_automatiquement_en_instruction do
|
||||||
transitions from: :en_construction, to: :en_instruction
|
transitions from: :en_construction, to: :en_instruction, guard: :can_passer_automatiquement_en_instruction?
|
||||||
end
|
end
|
||||||
|
|
||||||
event :repasser_en_construction, after: :after_repasser_en_construction do
|
event :repasser_en_construction, after: :after_repasser_en_construction do
|
||||||
|
@ -181,7 +181,7 @@ class Dossier < ApplicationRecord
|
||||||
end
|
end
|
||||||
|
|
||||||
event :accepter_automatiquement, after: :after_accepter_automatiquement do
|
event :accepter_automatiquement, after: :after_accepter_automatiquement do
|
||||||
transitions from: :en_construction, to: :accepte, guard: :can_terminer?
|
transitions from: :en_construction, to: :accepte, guard: :can_accepter_automatiquement?
|
||||||
end
|
end
|
||||||
|
|
||||||
event :refuser, after: :after_refuser do
|
event :refuser, after: :after_refuser do
|
||||||
|
@ -526,6 +526,14 @@ class Dossier < ApplicationRecord
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def can_accepter_automatiquement?
|
||||||
|
declarative_triggered_at.nil? && can_terminer?
|
||||||
|
end
|
||||||
|
|
||||||
|
def can_passer_automatiquement_en_instruction?
|
||||||
|
declarative_triggered_at.nil?
|
||||||
|
end
|
||||||
|
|
||||||
def can_repasser_en_instruction?
|
def can_repasser_en_instruction?
|
||||||
termine? && !user_deleted?
|
termine? && !user_deleted?
|
||||||
end
|
end
|
||||||
|
@ -978,6 +986,14 @@ class Dossier < ApplicationRecord
|
||||||
log_dossier_operation(instructeur, :classer_sans_suite, self)
|
log_dossier_operation(instructeur, :classer_sans_suite, self)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def process_declarative!
|
||||||
|
if procedure.declarative_accepte? && may_accepter_automatiquement?
|
||||||
|
accepter_automatiquement!
|
||||||
|
elsif procedure.declarative_en_instruction? && may_passer_automatiquement_en_instruction?
|
||||||
|
passer_automatiquement_en_instruction!
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def remove_titres_identite!
|
def remove_titres_identite!
|
||||||
champs_public.filter(&:titre_identite?).map(&:piece_justificative_file).each(&:purge_later)
|
champs_public.filter(&:titre_identite?).map(&:piece_justificative_file).each(&:purge_later)
|
||||||
end
|
end
|
||||||
|
|
|
@ -447,6 +447,10 @@ class Procedure < ApplicationRecord
|
||||||
declarative_with_state == Procedure.declarative_with_states.fetch(:accepte)
|
declarative_with_state == Procedure.declarative_with_states.fetch(:accepte)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def declarative_en_instruction?
|
||||||
|
declarative_with_state == Procedure.declarative_with_states.fetch(:en_instruction)
|
||||||
|
end
|
||||||
|
|
||||||
def self.declarative_attributes_for_select
|
def self.declarative_attributes_for_select
|
||||||
declarative_with_states.map do |state, _|
|
declarative_with_states.map do |state, _|
|
||||||
[I18n.t("activerecord.attributes.#{model_name.i18n_key}.declarative_with_state/#{state}"), state]
|
[I18n.t("activerecord.attributes.#{model_name.i18n_key}.declarative_with_state/#{state}"), state]
|
||||||
|
@ -635,23 +639,6 @@ class Procedure < ApplicationRecord
|
||||||
result
|
result
|
||||||
end
|
end
|
||||||
|
|
||||||
def process_dossiers!
|
|
||||||
case declarative_with_state
|
|
||||||
when Procedure.declarative_with_states.fetch(:en_instruction)
|
|
||||||
dossiers
|
|
||||||
.state_en_construction
|
|
||||||
.where(declarative_triggered_at: nil)
|
|
||||||
.find_each(&:passer_automatiquement_en_instruction!)
|
|
||||||
when Procedure.declarative_with_states.fetch(:accepte)
|
|
||||||
dossiers
|
|
||||||
.state_en_construction
|
|
||||||
.where(declarative_triggered_at: nil)
|
|
||||||
.find_each do |dossier|
|
|
||||||
dossier.accepter_automatiquement! if dossier.may_accepter_automatiquement?
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def logo_url
|
def logo_url
|
||||||
if logo.attached?
|
if logo.attached?
|
||||||
Rails.application.routes.url_helpers.url_for(logo)
|
Rails.application.routes.url_helpers.url_for(logo)
|
||||||
|
|
|
@ -1,124 +0,0 @@
|
||||||
RSpec.describe Cron::DeclarativeProceduresJob, type: :job do
|
|
||||||
describe "perform" do
|
|
||||||
let(:date) { Time.utc(2017, 9, 1, 10, 5, 0) }
|
|
||||||
let(:instruction_date) { date + 120 }
|
|
||||||
|
|
||||||
let(:state) { nil }
|
|
||||||
let(:procedure) { create(:procedure, :published, :for_individual, :with_instructeur, declarative_with_state: state) }
|
|
||||||
let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure: procedure) }
|
|
||||||
let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_individual, :with_attestation, procedure: procedure) }
|
|
||||||
let(:dossier_recu) { create(:dossier, :en_instruction, :with_individual, procedure: procedure) }
|
|
||||||
let(:dossier_brouillon) { create(:dossier, procedure: procedure) }
|
|
||||||
let(:dossier_repasse_en_construction) { create(:dossier, :en_construction, :with_individual, procedure: procedure) }
|
|
||||||
|
|
||||||
before do
|
|
||||||
Timecop.freeze(date)
|
|
||||||
dossier_repasse_en_construction&.touch(:declarative_triggered_at)
|
|
||||||
end
|
|
||||||
|
|
||||||
subject(:perform_job) do
|
|
||||||
dossiers = [
|
|
||||||
nouveau_dossier1,
|
|
||||||
nouveau_dossier2,
|
|
||||||
dossier_recu,
|
|
||||||
dossier_brouillon,
|
|
||||||
dossier_repasse_en_construction
|
|
||||||
].compact
|
|
||||||
|
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
|
||||||
|
|
||||||
dossiers.each(&:reload)
|
|
||||||
end
|
|
||||||
|
|
||||||
after { Timecop.return }
|
|
||||||
|
|
||||||
context "with some dossiers" do
|
|
||||||
context "en_construction" do
|
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
|
||||||
let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last }
|
|
||||||
|
|
||||||
it {
|
|
||||||
perform_job
|
|
||||||
expect(nouveau_dossier1.en_instruction?).to be_truthy
|
|
||||||
expect(nouveau_dossier1.en_instruction_at).to eq(date)
|
|
||||||
expect(last_operation.operation).to eq('passer_en_instruction')
|
|
||||||
expect(last_operation.automatic_operation?).to be_truthy
|
|
||||||
|
|
||||||
expect(nouveau_dossier2.en_instruction?).to be_truthy
|
|
||||||
expect(nouveau_dossier2.en_instruction_at).to eq(date)
|
|
||||||
|
|
||||||
expect(dossier_recu.en_instruction?).to be_truthy
|
|
||||||
expect(dossier_recu.en_instruction_at).to eq(instruction_date)
|
|
||||||
|
|
||||||
expect(dossier_brouillon.brouillon?).to be_truthy
|
|
||||||
expect(dossier_brouillon.en_instruction_at).to eq(nil)
|
|
||||||
|
|
||||||
expect(dossier_repasse_en_construction.en_construction?).to be_truthy
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
context "accepte" do
|
|
||||||
let(:state) { Dossier.states.fetch(:accepte) }
|
|
||||||
let(:last_operation) { nouveau_dossier1.dossier_operation_logs.last }
|
|
||||||
|
|
||||||
it {
|
|
||||||
perform_job
|
|
||||||
expect(nouveau_dossier1.accepte?).to be true
|
|
||||||
expect(nouveau_dossier1.en_instruction_at).to eq(date)
|
|
||||||
expect(nouveau_dossier1.processed_at).to eq(date)
|
|
||||||
expect(nouveau_dossier1.attestation).to be_present
|
|
||||||
expect(last_operation.operation).to eq('accepter')
|
|
||||||
expect(last_operation.automatic_operation?).to be_truthy
|
|
||||||
|
|
||||||
expect(nouveau_dossier2.accepte?).to be true
|
|
||||||
expect(nouveau_dossier2.en_instruction_at).to eq(date)
|
|
||||||
expect(nouveau_dossier2.processed_at).to eq(date)
|
|
||||||
expect(nouveau_dossier2.attestation).to be_present
|
|
||||||
|
|
||||||
expect(dossier_recu.en_instruction?).to be true
|
|
||||||
expect(dossier_recu.en_instruction_at).to eq(instruction_date)
|
|
||||||
expect(dossier_recu.processed_at).to eq(nil)
|
|
||||||
|
|
||||||
expect(dossier_brouillon.brouillon?).to be true
|
|
||||||
expect(dossier_brouillon.en_instruction_at).to eq(nil)
|
|
||||||
expect(dossier_brouillon.processed_at).to eq(nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
context "having etablissement in degraded_mode" do
|
|
||||||
let(:procedure) { create(:procedure, :published, :with_instructeur, for_individual: false, declarative_with_state: state) }
|
|
||||||
let(:nouveau_dossier1) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure: procedure, as_degraded_mode: false) }
|
|
||||||
let(:nouveau_dossier2) { create(:dossier, :en_construction, :with_entreprise, :with_attestation, procedure: procedure, as_degraded_mode: true) }
|
|
||||||
let(:dossier_recu) { nil }
|
|
||||||
let(:dossier_repasse_en_construction) { nil }
|
|
||||||
|
|
||||||
before do
|
|
||||||
expect(nouveau_dossier2).to_not receive(:accepter_automatiquement)
|
|
||||||
expect(Sentry).to_not receive(:capture_exception)
|
|
||||||
end
|
|
||||||
|
|
||||||
it {
|
|
||||||
perform_job
|
|
||||||
expect(nouveau_dossier1).to be_accepte
|
|
||||||
expect(nouveau_dossier2).to be_en_construction
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'safer perform' do
|
|
||||||
let(:state) { Dossier.states.fetch(:en_instruction) }
|
|
||||||
|
|
||||||
it 'works no matter if one raise' do
|
|
||||||
procedure_1 = instance_double("Procedure")
|
|
||||||
expect(procedure_1).to receive(:process_dossiers!)
|
|
||||||
procedure_2 = instance_double("Procedure")
|
|
||||||
expect(procedure_2).to receive(:process_dossiers!).and_raise("boom")
|
|
||||||
procedure_3 = double(process_dossiers!: true)
|
|
||||||
expect(procedure_3).to receive(:process_dossiers!)
|
|
||||||
|
|
||||||
expect(Procedure).to receive_message_chain(:declarative, :find_each).and_yield(procedure_1).and_yield(procedure_2).and_yield(procedure_3)
|
|
||||||
Cron::DeclarativeProceduresJob.perform_now
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -186,7 +186,7 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#notifications_for_dossier' do
|
describe '#notifications_for_dossier' do
|
||||||
let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) }
|
let!(:dossier) { create(:dossier, :en_construction, :followed) }
|
||||||
let(:instructeur) { dossier.follows.first.instructeur }
|
let(:instructeur) { dossier.follows.first.instructeur }
|
||||||
|
|
||||||
subject { instructeur.notifications_for_dossier(dossier) }
|
subject { instructeur.notifications_for_dossier(dossier) }
|
||||||
|
@ -245,12 +245,12 @@ describe Instructeur, type: :model do
|
||||||
# a procedure, one group, 2 instructeurs
|
# a procedure, one group, 2 instructeurs
|
||||||
let(:procedure) { create(:simple_procedure, :routee, :with_type_de_champ_private, :for_individual) }
|
let(:procedure) { create(:simple_procedure, :routee, :with_type_de_champ_private, :for_individual) }
|
||||||
let(:gi_p1) { procedure.groupe_instructeurs.last }
|
let(:gi_p1) { procedure.groupe_instructeurs.last }
|
||||||
let!(:dossier) { create(:dossier, :with_individual, :followed, procedure: procedure, groupe_instructeur: gi_p1, state: Dossier.states.fetch(:en_construction)) }
|
let!(:dossier) { create(:dossier, :en_construction, :with_individual, :followed, procedure: procedure, groupe_instructeur: gi_p1) }
|
||||||
let(:instructeur) { dossier.follows.first.instructeur }
|
let(:instructeur) { dossier.follows.first.instructeur }
|
||||||
let!(:instructeur_2) { create(:instructeur, groupe_instructeurs: [gi_p1]) }
|
let!(:instructeur_2) { create(:instructeur, groupe_instructeurs: [gi_p1]) }
|
||||||
|
|
||||||
# another procedure, dossier followed by a third instructeur
|
# another procedure, dossier followed by a third instructeur
|
||||||
let!(:dossier_on_procedure_2) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) }
|
let!(:dossier_on_procedure_2) { create(:dossier, :en_construction, :followed) }
|
||||||
let!(:instructeur_on_procedure_2) { dossier_on_procedure_2.follows.first.instructeur }
|
let!(:instructeur_on_procedure_2) { dossier_on_procedure_2.follows.first.instructeur }
|
||||||
let(:gi_p2) { dossier.groupe_instructeur }
|
let(:gi_p2) { dossier.groupe_instructeur }
|
||||||
|
|
||||||
|
@ -355,7 +355,7 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#procedure_ids_with_notifications' do
|
describe '#procedure_ids_with_notifications' do
|
||||||
let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) }
|
let!(:dossier) { create(:dossier, :en_construction, :followed) }
|
||||||
let(:instructeur) { dossier.follows.first.instructeur }
|
let(:instructeur) { dossier.follows.first.instructeur }
|
||||||
let(:procedure) { dossier.procedure }
|
let(:procedure) { dossier.procedure }
|
||||||
|
|
||||||
|
@ -369,7 +369,7 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '#mark_tab_as_seen' do
|
describe '#mark_tab_as_seen' do
|
||||||
let!(:dossier) { create(:dossier, :followed, state: Dossier.states.fetch(:en_construction)) }
|
let!(:dossier) { create(:dossier, :en_construction, :followed) }
|
||||||
let(:instructeur) { dossier.follows.first.instructeur }
|
let(:instructeur) { dossier.follows.first.instructeur }
|
||||||
let(:freeze_date) { Time.zone.parse('12/12/2012') }
|
let(:freeze_date) { Time.zone.parse('12/12/2012') }
|
||||||
|
|
||||||
|
@ -416,7 +416,7 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a dossier in construction exists' do
|
context 'when a dossier in construction exists' do
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) }
|
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) }
|
||||||
|
|
||||||
it do
|
it do
|
||||||
expect(instructeur.email_notification_data).to eq([
|
expect(instructeur.email_notification_data).to eq([
|
||||||
|
@ -454,12 +454,11 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a declarated dossier in instruction exists' do
|
context 'when a declarated dossier in instruction exists' do
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
procedure_to_assign.update(declarative_with_state: "en_instruction")
|
procedure_to_assign.update!(declarative_with_state: "en_instruction")
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
dossier.process_declarative!
|
||||||
dossier.reload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(procedure_to_assign.declarative_with_state).to eq("en_instruction") }
|
it { expect(procedure_to_assign.declarative_with_state).to eq("en_instruction") }
|
||||||
|
@ -479,12 +478,11 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a declarated dossier in accepte processed at today exists' do
|
context 'when a declarated dossier in accepte processed at today exists' do
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
procedure_to_assign.update(declarative_with_state: "accepte")
|
procedure_to_assign.update(declarative_with_state: "accepte")
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
dossier.process_declarative!
|
||||||
dossier.reload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(procedure_to_assign.declarative_with_state).to eq("accepte") }
|
it { expect(procedure_to_assign.declarative_with_state).to eq("accepte") }
|
||||||
|
@ -496,13 +494,12 @@ describe Instructeur, type: :model do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a declarated dossier in accepte processed at yesterday exists' do
|
context 'when a declarated dossier in accepte processed at yesterday exists' do
|
||||||
let!(:dossier) { create(:dossier, procedure: procedure_to_assign, state: Dossier.states.fetch(:en_construction)) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure_to_assign) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
procedure_to_assign.update(declarative_with_state: "accepte")
|
procedure_to_assign.update(declarative_with_state: "accepte")
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
dossier.process_declarative!
|
||||||
dossier.traitements.last.update(processed_at: Time.zone.yesterday.beginning_of_day)
|
dossier.traitements.last.update(processed_at: Time.zone.yesterday.beginning_of_day)
|
||||||
dossier.reload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it { expect(procedure_to_assign.declarative_with_state).to eq("accepte") }
|
it { expect(procedure_to_assign.declarative_with_state).to eq("accepte") }
|
||||||
|
|
|
@ -48,11 +48,10 @@ describe NotificationService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a declarative dossier in instruction exists on this procedure' do
|
context 'when a declarative dossier in instruction exists on this procedure' do
|
||||||
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
before do
|
before do
|
||||||
procedure.update(declarative_with_state: "en_instruction")
|
procedure.update(declarative_with_state: "en_instruction")
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
dossier.process_declarative!
|
||||||
dossier.reload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
|
@ -62,12 +61,11 @@ describe NotificationService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a declarative dossier in accepte on yesterday exists on this procedure' do
|
context 'when a declarative dossier in accepte on yesterday exists on this procedure' do
|
||||||
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
before do
|
before do
|
||||||
procedure.update(declarative_with_state: "accepte")
|
procedure.update(declarative_with_state: "accepte")
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
dossier.process_declarative!
|
||||||
dossier.traitements.last.update!(processed_at: Time.zone.yesterday.beginning_of_day)
|
dossier.traitements.last.update!(processed_at: Time.zone.yesterday.beginning_of_day)
|
||||||
dossier.reload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
|
@ -77,11 +75,10 @@ describe NotificationService do
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when a declarative dossier in accepte on today exists on this procedure' do
|
context 'when a declarative dossier in accepte on today exists on this procedure' do
|
||||||
let!(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
let(:dossier) { create(:dossier, :en_construction, procedure: procedure) }
|
||||||
before do
|
before do
|
||||||
procedure.update(declarative_with_state: "accepte")
|
procedure.update(declarative_with_state: "accepte")
|
||||||
Cron::DeclarativeProceduresJob.new.perform
|
dossier.process_declarative!
|
||||||
dossier.reload
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it do
|
it do
|
||||||
|
|
Loading…
Reference in a new issue