Class: BatchesController

Inherits:
ApplicationController show all
Defined in:
app/controllers/batches_controller.rb

Overview

Batches represent collections of requests processed through a Pipeline at the same time. They are created via selecting requests on the pipelines show page

Constant Summary

Constants included from FlashTruncation

FlashTruncation::STRING_OVERHEAD

Instance Method Summary collapse

Methods inherited from ApplicationController

#block_api_access, #clean_params_from_check, #evil_parameter_hack!, #extract_header_info, #set_cache_disabled!

Methods included from FlashTruncation

#max_flash_size, #truncate_flash, #truncate_flash_array

Instance Method Details

#batch_parametersObject


88
89
90
# File 'app/controllers/batches_controller.rb', line 88

def batch_parameters
  @batch_parameters ||= params.require(:batch).permit(:assignee_id)
end

#completedObject


151
152
153
154
155
156
# File 'app/controllers/batches_controller.rb', line 151

def completed
  # The params fall-back here reflects an older route where pipeline got passed in as :id. It should be removed
  # in the near future.
  @pipeline = Pipeline.find(params[:pipeline_id] || params[:id])
  @batches = @pipeline.batches.completed.order(id: :desc).includes(%i[user pipeline]).page(params[:page])
end

#createObject


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'app/controllers/batches_controller.rb', line 92

def create
  @pipeline = Pipeline.find(params[:id])

  requests = @pipeline.extract_requests_from_input_params(request_parameters)

  # TODO: These should be different endpoints
  case params[:action_on_requests]
  when 'cancel_requests'
    transition_requests(requests, :cancel_before_started!, 'Requests cancelled')
  when 'hide_from_inbox'
    transition_requests(requests, :hold!, 'Requests hidden from inbox')
  else
    # This is the standard create action
    standard_create(requests)
  end
rescue ActiveRecord::RecordInvalid => e
  respond_to do |format|
    format.html do
      flash[:error] = e.record.errors.full_messages
      redirect_to(pipeline_path(@pipeline))
    end
    format.xml { render xml: @batch.errors.to_xml }
  end
end

#download_spreadsheetObject

Used in Cherrypicking pipeline to generate the template for CSV driven picks


350
351
352
353
354
355
# File 'app/controllers/batches_controller.rb', line 350

def download_spreadsheet
  csv_string = Tasks::PlateTemplateHandler.generate_spreadsheet(@batch)
  send_data csv_string, type: 'text/plain',
                        filename: "#{@batch.id}_cherrypick_layout.csv",
                        disposition: 'attachment'
end

#editObject


61
62
63
64
65
66
# File 'app/controllers/batches_controller.rb', line 61

def edit
  @rits = @batch.pipeline.request_information_types
  @requests = @batch.ordered_requests.includes(:batch_request, :asset, :target_asset, :comments)
  @users = User.all
  @controls = @batch.pipeline.controls
end

#failObject


165
166
167
168
169
170
171
# File 'app/controllers/batches_controller.rb', line 165

def fail
  @fail_reasons = if @batch.workflow.source_is_internal?
                    FAILURE_REASONS['internal']
                  else
                    FAILURE_REASONS['external']
                  end
end

#fail_itemsObject


173
174
175
176
177
178
179
180
181
182
183
184
185
# File 'app/controllers/batches_controller.rb', line 173

def fail_items
  ActiveRecord::Base.transaction do
    fail_params = params.permit(:id, requested_fail: {}, requested_remove: {},
                                     failure: %i[reason comment fail_but_charge])
    fail_and_remover = Batch::RequestFailAndRemover.new(fail_params)
    if fail_and_remover.save
      flash[:notice] = truncate_flash(fail_and_remover.notice)
    else
      flash[:error] = truncate_flash(fail_and_remover.errors.full_messages.join(';'))
    end
    redirect_to action: :fail, id: params[:id]
  end
end

#failedObject


158
159
160
161
162
163
# File 'app/controllers/batches_controller.rb', line 158

def failed
  # The params fall-back here reflects an older route where pipeline got passed in as :id. It should be removed
  # in the near future.
  @pipeline = Pipeline.find(params[:pipeline_id] || params[:id])
  @batches = @pipeline.batches.failed.order(id: :desc).includes(%i[user pipeline]).page(params[:page])
end

#filteredObject


336
# File 'app/controllers/batches_controller.rb', line 336

def filtered; end

#find_batch_by_barcodeObject


379
380
381
382
383
384
385
386
387
388
389
# File 'app/controllers/batches_controller.rb', line 379

def find_batch_by_barcode
  batch_id = LabEvent.find_batch_id_by_barcode(params[:id])
  if batch_id.nil?
    @batch_error = 'Batch id not found.'
    render action: 'batch_error', format: :xml
    nil
  else
    @batch = Batch.find(batch_id)
    render action: 'show', format: :xml
  end
end

#find_batch_by_batch_idObject


361
362
363
# File 'app/controllers/batches_controller.rb', line 361

def find_batch_by_batch_id
  @batch = Batch.find(params[:batch_id])
end

#find_batch_by_idObject


357
358
359
# File 'app/controllers/batches_controller.rb', line 357

def find_batch_by_id
  @batch = Batch.find(params[:id])
end

#indexObject


20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'app/controllers/batches_controller.rb', line 20

def index
  if logged_in?
    @user = params.fetch(:user, current_user)
    @batches = Batch.for_user(@user)
                    .order(id: :desc)
                    .includes(:user, :assignee, :pipeline)
                    .page(params[:page])
  else
    # Can end up here with XML. And it causes pain.
    @batches = Batch.order(id: :asc).page(params[:page]).limit(10)
  end
  respond_to do |format|
    format.html
    format.xml { render xml: @batches.to_xml }
    format.json { render json: @batches.to_json.gsub(/null/, '""') }
  end
end

#pacbio_sample_sheetObject


365
366
367
368
369
370
# File 'app/controllers/batches_controller.rb', line 365

def pacbio_sample_sheet
  csv_string = PacBio::SampleSheet.new.create_csv_from_batch(@batch)
  send_data csv_string, type: 'text/plain',
                        filename: "batch_#{@batch.id}_sample_sheet.csv",
                        disposition: 'attachment'
end

#pendingObject


125
126
127
128
129
130
# File 'app/controllers/batches_controller.rb', line 125

def pending
  # The params fall-back here reflects an older route where pipeline got passed in as :id. It should be removed
  # in the near future.
  @pipeline = Pipeline.find(params[:pipeline_id] || params[:id])
  @batches = @pipeline.batches.pending.order(id: :desc).includes(%i[user pipeline]).page(params[:page])
end

#pipelineObject


117
118
119
120
121
122
123
# File 'app/controllers/batches_controller.rb', line 117

def pipeline
  # All pipeline batches routes should just direct to batches#index with pipeline and state as filter parameters
  @batches = Batch.where(pipeline_id: params[:pipeline_id] || params[:id])
                  .order(id: :desc)
                  .includes(:user, :pipeline)
                  .page(params[:page])
end

#previous_qc_stateObject


329
330
331
332
333
334
# File 'app/controllers/batches_controller.rb', line 329

def previous_qc_state
  @batch.qc_previous_state!(current_user)
  @batch.save
  flash[:notice] = "Batch #{@batch.id} reset to state #{@batch.qc_state}"
  redirect_to batch_url(@batch)
end

278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
# File 'app/controllers/batches_controller.rb', line 278

def print
  @task     = Task.find(params[:task_id]) if params[:task_id]
  @workflow = @batch.workflow
  @pipeline = @batch.pipeline
  @comments = @batch.comments

  robot_id = params.fetch(:robot_id, @batch.robot_id)

  @robot = robot_id ? Robot.find(robot_id) : Robot.with_verification_behaviour.first
  # Fall-back
  @robot ||= Robot.first

  if @pipeline.is_a?(CherrypickingPipeline)
    @plates = if params[:barcode]
                Plate.with_barcode(params[:barcode])
              else
                @batch.output_plates
              end
  end

  template = @pipeline.batch_worksheet
  render action: template, layout: false
end

269
270
271
272
273
274
275
276
# File 'app/controllers/batches_controller.rb', line 269

def print_barcodes
  if @batch.requests.empty?
    flash[:notice] = 'Your batch contains no requests.'
    redirect_to controller: 'batches', action: 'show', id: @batch.id
  else
    print_handler(LabelPrinter::Label::BatchTube)
  end
end

197
# File 'app/controllers/batches_controller.rb', line 197

def print_labels; end

261
262
263
# File 'app/controllers/batches_controller.rb', line 261

def print_multiplex_barcodes
  print_handler(LabelPrinter::Label::BatchMultiplex)
end

223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
# File 'app/controllers/batches_controller.rb', line 223

def print_multiplex_labels
  request = @batch.requests.first
  if request.tag_number.nil?
    flash[:error] = 'No tags have been assigned.'
  elsif request.target_asset.present? && request.target_asset.children.present?
    # We are trying to find the MX library tube or the stock MX library
    # tube. I've added a filter so it doesn't pick up Lanes.
    children = request.target_asset.children.last.children.select { |a| a.is_a?(Tube) }
    @asset = if children.empty?
               request.target_asset.children.last
             else
               request.target_asset.children.last.children.last
             end
  else
    flash[:notice] = 'There is no multiplexed library available.'
  end
end

265
266
267
# File 'app/controllers/batches_controller.rb', line 265

def print_plate_barcodes
  print_handler(LabelPrinter::Label::BatchRedirect)
end

203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'app/controllers/batches_controller.rb', line 203

def print_plate_labels
  @pipeline = @batch.pipeline
  @output_barcodes = []

  @output_labware = @batch.plate_group_barcodes || []

  @output_labware.each do |parent, _children|
    next if parent.nil?

    plate_barcode = parent.human_barcode
    @output_barcodes << plate_barcode if plate_barcode.present?
  end

  return if @output_barcodes.present?

  # We have no output barcodes, which means a problem
  flash[:error] = 'Output plates do not have barcodes to print'
  redirect_to controller: 'batches', action: 'show', id: @batch.id
end

199
200
201
# File 'app/controllers/batches_controller.rb', line 199

def print_stock_labels
  @batch = Batch.find(params[:id])
end

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'app/controllers/batches_controller.rb', line 241

def print_stock_multiplex_labels
  @batch = Batch.find(params[:id])
  request = @batch.requests.first
  pooled_library = request.target_asset.children.first
  stock_multiplexed_tube = nil

  if pooled_library.is_a_stock_asset?
    stock_multiplexed_tube = pooled_library
  elsif pooled_library.has_stock_asset?
    stock_multiplexed_tube = pooled_library.stock_asset
  end

  if stock_multiplexed_tube.nil?
    flash[:notice] = 'There is no stock multiplexed library available.'
    redirect_to controller: 'batches', action: 'show', id: @batch.id
  else
    @asset = stock_multiplexed_tube
  end
end

#releasedObject


139
140
141
142
143
144
145
146
147
148
149
# File 'app/controllers/batches_controller.rb', line 139

def released
  # The params fall-back here reflects an older route where pipeline got passed in as :id. It should be removed
  # in the near future.
  @pipeline = Pipeline.find(params[:pipeline_id] || params[:id])

  @batches = @pipeline.batches.released.order(id: :desc).includes(%i[user pipeline]).page(params[:page])
  respond_to do |format|
    format.html
    format.xml { render layout: false }
  end
end

#reset_batchObject


322
323
324
325
326
327
# File 'app/controllers/batches_controller.rb', line 322

def reset_batch
  pipeline = @batch.pipeline
  @batch.reset!(current_user)
  flash[:notice] = "Batch #{@batch.id} has been reset"
  redirect_to controller: 'pipelines', action: :show, id: pipeline.id
end

#sample_prep_worksheetObject


372
373
374
375
376
377
# File 'app/controllers/batches_controller.rb', line 372

def sample_prep_worksheet
  csv_string = PacBio::Worksheet.new.create_csv_from_batch(@batch)
  send_data csv_string, type: 'text/plain',
                        filename: "batch_#{@batch.id}_worksheet.csv",
                        disposition: 'attachment'
end

#saveObject


193
194
195
# File 'app/controllers/batches_controller.rb', line 193

def save
  redirect_to action: :show, id: @batch.id
end

#showObject


38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
# File 'app/controllers/batches_controller.rb', line 38

def show
  respond_to do |format|
    format.html do
      @submenu_presenter = Presenters::BatchSubmenuPresenter.new(current_user, @batch)

      @pipeline = @batch.pipeline
      @tasks    = @batch.tasks.sort_by(&:sorted)
      @rits = @pipeline.request_information_types
      @input_labware = @batch.input_labware_report
      @output_labware = @batch.output_labware_report

      if @pipeline.pick_data
        @robot = @batch.robot_id ? Robot.find(@batch.robot_id) : Robot.with_verification_behaviour.first
        # In the event we have no robots with the correct behaviour, and none are specialised on the batch, fall-back
        # to the first robot.
        @robot ||= Robot.first
        @robots = Robot.with_verification_behaviour
      end
    end
    format.xml { render layout: false }
  end
end

#sortObject


187
188
189
190
191
# File 'app/controllers/batches_controller.rb', line 187

def sort
  @batch.assign_positions_to_requests!(params['requests_list'].map(&:to_i))
  @batch.rebroadcast
  head :ok
end

#startedObject


132
133
134
135
136
137
# File 'app/controllers/batches_controller.rb', line 132

def started
  # The params fall-back here reflects an older route where pipeline got passed in as :id. It should be removed
  # in the near future.
  @pipeline = Pipeline.find(params[:pipeline_id] || params[:id])
  @batches = @pipeline.batches.started.order(id: :desc).includes(%i[user pipeline]).page(params[:page])
end

#swapObject


338
339
340
341
342
343
344
345
346
347
# File 'app/controllers/batches_controller.rb', line 338

def swap
  if @batch.swap(current_user, 'batch_1' => { 'id' => params['batch']['1'], 'lane' => params['batch']['position']['1'] },
                               'batch_2' => { 'id' => params['batch']['2'], 'lane' => params['batch']['position']['2'] })
    flash[:notice] = 'Successfully swapped lane positions'
    redirect_to batch_path(@batch)
  else
    flash[:error] = @batch.errors.full_messages.join('<br />')
    redirect_to action: :filtered, id: @batch.id
  end
end

#updateObject


68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'app/controllers/batches_controller.rb', line 68

def update
  if batch_parameters[:assignee_id]
    user = User.find(batch_parameters[:assignee_id])
    assigned_message = "Assigned to #{user.name} (#{user.})."
  else
    assigned_message = ''
  end

  respond_to do |format|
    if @batch.update(batch_parameters)
      flash[:notice] = "Batch was successfully updated. #{assigned_message}"
      format.html { redirect_to batch_url(@batch) }
      format.xml  { head :ok }
    else
      format.html { render action: 'edit' }
      format.xml  { render xml: @batch.errors.to_xml }
    end
  end
end

#verifyObject


302
303
304
305
306
# File 'app/controllers/batches_controller.rb', line 302

def verify
  @requests = @batch.ordered_requests
  @pipeline = @batch.pipeline
  @count = @requests.length
end

#verify_tube_layoutObject


308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'app/controllers/batches_controller.rb', line 308

def verify_tube_layout
  tube_barcodes = Array.new(@batch.requests.count) { |i| params["barcode_#{i}"] }

  results = @batch.verify_tube_layout(tube_barcodes, current_user)

  if results
    flash[:notice] = 'All of the tubes are in their correct positions.'
    redirect_to batch_path(@batch)
  elsif !results
    flash[:error] = @batch.errors.full_messages.sort
    redirect_to action: :verify, id: @batch.id
  end
end