diff --git a/app/controllers/instructeurs/batch_operations_controller.rb b/app/controllers/instructeurs/batch_operations_controller.rb new file mode 100644 index 000000000..722bdacdb --- /dev/null +++ b/app/controllers/instructeurs/batch_operations_controller.rb @@ -0,0 +1,34 @@ +module Instructeurs + class BatchOperationsController < ApplicationController + before_action :set_procedure + before_action :ensure_ownership! + + def create + ActiveRecord::Base.transaction do + batch_operation = BatchOperation.create!(batch_operation_params.merge(instructeur: current_instructeur)) + BatchOperationEnqueueAllJob.perform_later(batch_operation) + end + redirect_back(fallback_location: instructeur_procedure_url(@procedure.id)) + end + + private + + def batch_operation_params + params.require(:batch_operation) + .permit(:operation, dossier_ids: []).tap do |params| + # TODO: filter dossiers_ids out of instructeurs.dossiers.ids + end + end + + def set_procedure + @procedure = Procedure.find(params[:procedure_id]) + end + + def ensure_ownership! + if !current_instructeur.procedures.exists?(@procedure.id) + flash[:alert] = "Vous n’avez pas accès à cette démarche" + redirect_to root_path + end + end + end +end diff --git a/app/jobs/batch_operation_enqueue_all_job.rb b/app/jobs/batch_operation_enqueue_all_job.rb new file mode 100644 index 000000000..2edc6d62b --- /dev/null +++ b/app/jobs/batch_operation_enqueue_all_job.rb @@ -0,0 +1,6 @@ +class BatchOperationEnqueueAllJob < ApplicationJob + def perform(batch_operation) + batch_operation.enqueue_all + end +end + diff --git a/app/jobs/batch_operation_job.rb b/app/jobs/batch_operation_process_one_job.rb similarity index 95% rename from app/jobs/batch_operation_job.rb rename to app/jobs/batch_operation_process_one_job.rb index 2f534a575..dd6e3abdd 100644 --- a/app/jobs/batch_operation_job.rb +++ b/app/jobs/batch_operation_process_one_job.rb @@ -1,4 +1,4 @@ -class BatchOperationJob < ApplicationJob +class BatchOperationProcessOneJob < ApplicationJob # what about wrapping all of that in a transaction # but, what about nested transaction because batch_operation.process_one(dossier) can run transaction def perform(batch_operation, dossier) diff --git a/app/models/batch_operation.rb b/app/models/batch_operation.rb index 8d0dd7a22..11eb1e32a 100644 --- a/app/models/batch_operation.rb +++ b/app/models/batch_operation.rb @@ -21,6 +21,7 @@ class BatchOperation < ApplicationRecord has_many :dossiers, dependent: :nullify belongs_to :instructeur + validates :operation, presence: true def enqueue_all diff --git a/config/routes.rb b/config/routes.rb index d83c877e3..d745204a6 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -414,6 +414,8 @@ Rails.application.routes.draw do get 'telecharger_pjs' => 'dossiers#telecharger_pjs' end end + + resources :batch_operations, only: [:create] end end end diff --git a/spec/controllers/instructeurs/batch_operations_controller_spec.rb b/spec/controllers/instructeurs/batch_operations_controller_spec.rb new file mode 100644 index 000000000..b21fabb27 --- /dev/null +++ b/spec/controllers/instructeurs/batch_operations_controller_spec.rb @@ -0,0 +1,44 @@ +# frozen_string_literal: true + +describe Instructeurs::BatchOperationsController, type: :controller do + let(:instructeur) { create(:instructeur) } + let(:procedure) { create(:procedure, :published, :for_individual, instructeurs: [instructeur]) } + let!(:dossier) { create(:dossier, :en_construction, :with_individual, procedure: procedure) } + + describe '#POST create' do + before { sign_in(instructeur.user) } + + context 'ACL' do + subject { post :create, params: { procedure_id: create(:procedure).id } } + before { sign_in(instructeur.user) } + it 'fails when procedure does not belongs to instructeur' do + expect(subject).to have_http_status(302) + end + end + + context 'success' do + let(:params) do + { + procedure_id: procedure.id, + batch_operation: { + operation: BatchOperation.operations.fetch(:archiver), + dossier_ids: [ dossier.id ] + } + } + end + subject { post :create, params: params } + before { sign_in(instructeur.user) } + it 'creates a batch operation for our signed in instructeur' do + expect { subject }.to change { instructeur.batch_operations.count }.by(1) + expect(BatchOperation.first.dossiers).to include(dossier) + end + it 'created a batch operation contains dossiers' do + subject + expect(BatchOperation.first.dossiers).to include(dossier) + end + it 'enqueues a BatchOperationJob' do + expect {subject}.to have_enqueued_job(BatchOperationEnqueueAllJob).with(BatchOperation.last) + end + end + end +end diff --git a/spec/factories/batch_operation.rb b/spec/factories/batch_operation.rb index 12e4a312f..3c5bcb068 100644 --- a/spec/factories/batch_operation.rb +++ b/spec/factories/batch_operation.rb @@ -1,12 +1,16 @@ FactoryBot.define do factory :batch_operation do + transient do + invalid_instructeur { nil } + end trait :archiver do operation { BatchOperation.operations.fetch(:archiver) } - dossiers do - [ - association(:dossier, :accepte), - association(:dossier, :refuse), - association(:dossier, :sans_suite) + after(:build) do |batch_operation, _evaluator| + procedure = create(:procedure, instructeurs: [_evaluator.invalid_instructeur.presence || batch_operation.instructeur]) + batch_operation.dossiers = [ + build(:dossier, :accepte, procedure: procedure), + build(:dossier, :refuse, procedure: procedure), + build(:dossier, :sans_suite, procedure: procedure) ] end end diff --git a/spec/jobs/batch_operation_job_spec.rb b/spec/jobs/batch_operation_process_one_job_spec.rb similarity index 94% rename from spec/jobs/batch_operation_job_spec.rb rename to spec/jobs/batch_operation_process_one_job_spec.rb index a2a2a6dd8..8e59a9857 100644 --- a/spec/jobs/batch_operation_job_spec.rb +++ b/spec/jobs/batch_operation_process_one_job_spec.rb @@ -1,11 +1,11 @@ -describe BatchOperationJob, type: :job do +describe BatchOperationProcessOneJob, type: :job do describe 'perform' do let(:batch_operation) do create(:batch_operation, :archiver, options.merge(instructeur: create(:instructeur))) end let(:dossier_job) { batch_operation.dossiers.first } - subject { BatchOperationJob.new(batch_operation, dossier_job) } + subject { BatchOperationProcessOneJob.new(batch_operation, dossier_job) } let(:options) { {} } it 'just call the process one' do