Class: Form526Submission

Inherits:
ApplicationRecord show all
Extended by:
Logging::ThirdPartyTransaction::MethodWrapper
Includes:
Form526ClaimFastTrackingConcern, Scopes::Form526SubmissionState, SentryLogging
Defined in:
app/models/form526_submission.rb

Constant Summary collapse

FORM_526 =
'form526'
FORM_526_UPLOADS =
'form526_uploads'
FORM_4142 =
'form4142'
FORM_0781 =
'form0781'
FORM_8940 =
'form8940'
FLASHES =
'flashes'
BIRLS_KEY =
'va_eauth_birlsfilenumber'
SUBMIT_FORM_526_JOB_CLASSES =
%w[SubmitForm526AllClaim SubmitForm526].freeze
MAX_PENDING_TIME =

MAX_PENDING_TIME aligns with the farthest out expectation given in the LH BI docs, plus 1 week to accomodate for edge cases and our sidekiq jobs

3.weeks
ZSF_DD_TAG_SERVICE =
'disability-application'

Constants included from Form526ClaimFastTrackingConcern

Form526ClaimFastTrackingConcern::CLAIM_REVIEW_BASE_CODES, Form526ClaimFastTrackingConcern::CLAIM_REVIEW_TYPES, Form526ClaimFastTrackingConcern::DOCUMENT_NAME_PREFIX, Form526ClaimFastTrackingConcern::DOCUMENT_NAME_SUFFIX, Form526ClaimFastTrackingConcern::EP_MERGE_BASE_CODES, Form526ClaimFastTrackingConcern::EP_MERGE_SPECIAL_ISSUE, Form526ClaimFastTrackingConcern::EP_MERGE_STATSD_KEY_PREFIX, Form526ClaimFastTrackingConcern::FLASHES_STATSD_KEY, Form526ClaimFastTrackingConcern::FLASH_PROTOTYPES, Form526ClaimFastTrackingConcern::MAX_CFI_STATSD_KEY_PREFIX, Form526ClaimFastTrackingConcern::OPEN_STATUSES, Form526ClaimFastTrackingConcern::PDF_FILENAME_REGEX, Form526ClaimFastTrackingConcern::RRD_CODE, Form526ClaimFastTrackingConcern::RRD_STATSD_KEY_PREFIX

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Logging::ThirdPartyTransaction::MethodWrapper

wrap_with_logging

Methods included from Form526ClaimFastTrackingConcern

#add_ep_merge_special_issue!, #all_rated_disabilities, #cfi_checkbox_was_selected?, #claim_age_in_days, #classify_vagov_contentions, #conditionally_merge_ep, #conditionally_notify_mas, #diagnostic_codes, #disabilities, #disabilities_not_service_connected?, #ep_merge_feature_enabled?, #flashes, #format_contention_for_vro, #in_progress_form, #increase_disabilities, #log_and_halt_if_no_disabilities, #log_claim_level_metrics, #log_flashes, #log_max_cfi_metrics_on_submit, #max_rated_diagnostic_codes_from_ipf, #max_rated_disabilities_from_ipf, #notify_mas_all_claims_tracking, #open_claim_review?, #open_claims, #pending_eps?, #prepare_for_ep_merge!, #prepare_for_evss!, #read_metadata, #rrd_claim_processed?, #rrd_pdf_added_for_uploading?, #rrd_pdf_created?, #rrd_pdf_uploaded_to_s3?, #rrd_special_issue_set?, #rrd_status, #save_metadata, #send_post_evss_notifications!, #send_rrd_alert_email, #update_contention_classification_all!, #update_form_with_classification_codes

Methods included from SentryLogging

#log_exception_to_sentry, #log_message_to_sentry, #non_nil_hash?, #normalize_level, #rails_logger, #set_sentry_metadata

Methods inherited from ApplicationRecord

descendants_using_encryption, lockbox_options, #timestamp_attributes_for_update_in_model, #valid?

Instance Attribute Details

#auth_headers_jsonString

Returns encrypted EVSS auth headers as JSON EVSS::DisabilityCompensationAuthHeaders.

Returns:



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#created_atTimestamp

Returns created at date.

Returns:

  • (Timestamp)

    created at date.



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#form_jsonString

Returns encrypted form submission as JSON.

Returns:

  • (String)

    encrypted form submission as JSON.



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#idInteger

Returns auto-increment primary key.

Returns:

  • (Integer)

    auto-increment primary key.



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#lighthouse_validation_responseObject (private)

Returns the value of attribute lighthouse_validation_response.



487
488
489
# File 'app/models/form526_submission.rb', line 487

def lighthouse_validation_response
  @lighthouse_validation_response
end

#saved_claim_idInteger

Returns the related saved claim id SavedClaim::DisabilityCompensation.

Returns:



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#updated_atTimestamp

Returns updated at date.

Returns:

  • (Timestamp)

    updated at date.



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#user_uuidString

Returns points to the user’s uuid from the identity provider.

Returns:

  • (String)

    points to the user’s uuid from the identity provider.



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

#workflow_completeBoolean

Returns are all the steps (jobs EVSS::DisabilityCompensationForm::Job) of the submission workflow complete.

Returns:



54
# File 'app/models/form526_submission.rb', line 54

has_kms_key

Instance Method Details

#a_submit_form_526_job_succeeded?Boolean

Returns:

  • (Boolean)


295
296
297
298
299
300
301
302
303
304
305
# File 'app/models/form526_submission.rb', line 295

def a_submit_form_526_job_succeeded?
  submit_form_526_job_statuses = form526_job_statuses.where(job_class: SUBMIT_FORM_526_JOB_CLASSES).order(:updated_at)
  submit_form_526_job_statuses.presence&.any?(&:success?)
ensure
  successful = submit_form_526_job_statuses.where(status: 'success').load
  warn = ->(message) { log_message_to_sentry(message, :warn, { form_526_submission_id: id }) }
  warn.call 'There are multiple successful SubmitForm526 job statuses' if successful.size > 1
  if successful.size == 1 && submit_form_526_job_statuses.last.unsuccessful?
    warn.call "There is a successful SubmitForm526 job, but it's not the most recent SubmitForm526 job"
  end
end

#accountObject



458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
# File 'app/models/form526_submission.rb', line 458

def 
  # first, check for an ICN on the UserAccount associated to the submission, return it if found
   = 
  return  if &.icn.present?

  # next, check past submissions for different UserAccounts that might have ICNs
  past_submissions = get_past_submissions
   = (past_submissions, 'past submissions')
  return  if .present? && .icn.present?

  # next, check for any historical UserAccounts for that user which might have an ICN
  user_verifications = get_user_verifications
   = (user_verifications, 'user verifications')
  return  if .present? && .icn.present?

  # failing all the above, default to an Account lookup
  Account.lookup_by_user_uuid(user_uuid)
end

#add_birls_ids(id_or_ids) ⇒ Object

this method is for queuing up BIRLS ids in the birls_ids_tried hash, and can also be used for initializing birls_ids_tried. birls_ids_tried has this shape:

birls_id => [timestamp, timestamp, ...],
birls_id => [timestamp, timestamp, ...], # in practice, will be only 1 timestamp
...

where each timestamp notes when a submissison job (start) was started with that BIRLS id (birls_id_tried keeps track of which BIRLS id have been tried so far). add_birls_ids does not overwrite birls_ids_tried. example: > sub.birls_ids_tried = { ‘111’ => [‘2021-01-01T0000Z’] } > sub.add_birls_ids [‘111’, ‘222’, ‘333’] > pp sub.birls_ids_tried

{
  '111' => ['2021-01-01T0000Z'], # a tried BIRLS ID
  '222' => [],  # an untried BIRLS ID
  '333' => []   # an untried BIRLS ID
}

NOTE: ‘111’ was not cleared



228
229
230
231
232
233
234
235
# File 'app/models/form526_submission.rb', line 228

def add_birls_ids(id_or_ids)
  ids = Array.wrap(id_or_ids).map { |id| id.is_a?(Symbol) ? id.to_s : id }
  hash = birls_ids_tried_hash
  ids.each { |id| hash[id] ||= [] }
  self.birls_ids_tried = hash.to_json
  self.multiple_birls = true if birls_ids.length > 1
  ids
end

#all_other_jobs_succeeded_if_any?Boolean

Returns:

  • (Boolean)


307
308
309
# File 'app/models/form526_submission.rb', line 307

def all_other_jobs_succeeded_if_any?
  form526_job_statuses.where.not(job_class: SUBMIT_FORM_526_JOB_CLASSES).all?(&:success?)
end

#auth_headersHash

Returns parsed auth headers.

Returns:

  • (Hash)

    parsed auth headers



202
203
204
# File 'app/models/form526_submission.rb', line 202

def auth_headers
  @auth_headers_hash ||= JSON.parse(auth_headers_json)
end

#bdd?Boolean

Returns:

  • (Boolean)


361
362
363
# File 'app/models/form526_submission.rb', line 361

def bdd?
  form.dig('form526', 'form526', 'bddQualified') || false
end

#birls_idObject



268
269
270
# File 'app/models/form526_submission.rb', line 268

def birls_id
  birls_id! if auth_headers_json
end

#birls_id!Object



264
265
266
# File 'app/models/form526_submission.rb', line 264

def birls_id!
  auth_headers[BIRLS_KEY]
end

#birls_id=(value) ⇒ Object



272
273
274
275
276
277
# File 'app/models/form526_submission.rb', line 272

def birls_id=(value)
  headers = JSON.parse(auth_headers_json) || {}
  headers[BIRLS_KEY] = value
  self.auth_headers_json = headers.to_json
  @auth_headers_hash = nil # reset cache
end

#birls_idsObject



237
238
239
# File 'app/models/form526_submission.rb', line 237

def birls_ids
  [*birls_ids_tried_hash&.keys, birls_id].compact.uniq
end

#birls_ids_that_havent_been_tried_yetObject



259
260
261
262
# File 'app/models/form526_submission.rb', line 259

def birls_ids_that_havent_been_tried_yet
  add_birls_ids birls_id if birls_id.present?
  birls_ids_tried_hash.select { |_id, timestamps| timestamps.blank? }.keys
end

#birls_ids_tried_hashObject



241
242
243
# File 'app/models/form526_submission.rb', line 241

def birls_ids_tried_hash
  birls_ids_tried.presence&.then { |json| JSON.parse json } || {}
end

#cleanupObject (private)



590
591
592
# File 'app/models/form526_submission.rb', line 590

def cleanup
  EVSS::DisabilityCompensationForm::SubmitForm526Cleanup.perform_async(id)
end

#conditionally_submit_form_4142Object (private)



479
480
481
482
483
484
485
# File 'app/models/form526_submission.rb', line 479

def conditionally_submit_form_4142
  if Flipper.enabled?(:disability_compensation_production_tester, OpenStruct.new({ flipper_id: user_uuid }))
    Rails.logger.info("submit_form_4142 call skipped for submission #{id}")
  elsif form[FORM_4142].present?
    submit_form_4142
  end
end

#duplicate?Boolean

Returns:

  • (Boolean)


434
435
436
# File 'app/models/form526_submission.rb', line 434

def duplicate?
  last_remediation&.ignored_as_duplicate?
end

#enqueue_backup_submission(id) ⇒ Object (private)



544
545
546
# File 'app/models/form526_submission.rb', line 544

def enqueue_backup_submission(id)
  Sidekiq::Form526BackupSubmissionProcess::Submit.perform_async(id)
end

#failure_type?Boolean

Returns:

  • (Boolean)


442
443
444
# File 'app/models/form526_submission.rb', line 442

def failure_type?
  !success_type? && !in_process?
end

#find_user_account_with_icn(records, record_type) ⇒ Object (private)



594
595
596
597
598
599
600
601
602
603
# File 'app/models/form526_submission.rb', line 594

def (records, record_type)
  records.pluck(:user_account_id).uniq.each do ||
     = UserAccount.find()
    next if &.icn.blank?

    Rails.logger.info("ICN not found on submission #{id}, " \
                      "using ICN for user account #{} instead (based on #{record_type})")
    return 
  end
end

#formHash

form_json is memoized here so call invalidate_form_hash after updating form_json

Returns:

  • (Hash)

    parsed version of the form json



179
180
181
# File 'app/models/form526_submission.rb', line 179

def form
  @form_hash ||= JSON.parse(form_json)
end

#form_content_valid?Boolean

Synchronous access to Lighthouse API validation boolean for 526 submission Because this method hits an external API, there could be exceptions generated for non-200 response codes.

If return is false, then the errors are expected to be in the lighthouse_validation_errors Array of Hashes.

NOTE: This is a synchronous access to an external API

so should not be used within a request/response workflow.

Returns:

  • (Boolean)


395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
# File 'app/models/form526_submission.rb', line 395

def form_content_valid?
  transform_service = EVSS::DisabilityCompensationForm::Form526ToLighthouseTransform.new
  body = transform_service.transform(form['form526'])

  @lighthouse_validation_response = lighthouse_service.validate526(body)

  if lighthouse_validation_response&.status == 200
    true
  else
    mock_lighthouse_response(status: lighthouse_validation_response&.status)
    false
  end
rescue => e
  handle_validation_error(e)
  false
end

#form_to_json(item) ⇒ String

A 526 submission can include the 526 form submission, uploads, and ancillary items. This method returns a single item as JSON

Parameters:

  • item (String)

    the item key

Returns:

  • (String)

    the requested form object as JSON



196
197
198
# File 'app/models/form526_submission.rb', line 196

def form_to_json(item)
  form[item].to_json
end

#format_creation_time_for_mailersObject



379
380
381
382
# File 'app/models/form526_submission.rb', line 379

def format_creation_time_for_mailers
  # We display dates in mailers in the format "May 1, 2024 3:01 p.m. EDT"
  created_at.strftime('%B %-d, %Y %-l:%M %P %Z').sub(/([ap])m/, '\1.m.')
end

#full_nameHash

Checks against the User record first, and then resorts to checking the auth_headers for the name attributes if the User record doesn’t exist or contain the full name

Returns:

  • (Hash)

    of the user’s full name (first, middle, last, suffix)



164
165
166
167
168
169
170
171
172
173
174
# File 'app/models/form526_submission.rb', line 164

def full_name
  name_hash = User.find(user_uuid)&.full_name_normalized
  return name_hash if name_hash&.[](:first).present?

  {
    first: auth_headers&.dig('va_eauth_firstName')&.capitalize,
    middle: nil,
    last: auth_headers&.dig('va_eauth_lastName')&.capitalize,
    suffix: nil
  }
end

#get_first_nameObject

Note that the User record is cached in Redis – ‘User.redis_namespace_ttl`



153
154
155
156
157
# File 'app/models/form526_submission.rb', line 153

def get_first_name
  user = User.find(user_uuid)
  user&.first_name&.upcase.presence ||
    auth_headers&.dig('va_eauth_firstName')&.upcase
end

#get_past_submissionsObject (private)



605
606
607
# File 'app/models/form526_submission.rb', line 605

def get_past_submissions
  Form526Submission.where(user_uuid:).where.not(user_account_id:)
end

#get_user_verificationsObject (private)



609
610
611
612
613
614
615
616
# File 'app/models/form526_submission.rb', line 609

def get_user_verifications
  UserVerification.where(idme_uuid: user_uuid)
                  .or(UserVerification.where(backing_idme_uuid: user_uuid))
                  .or(UserVerification.where(logingov_uuid: user_uuid))
                  .or(UserVerification.where(mhv_uuid: user_uuid))
                  .or(UserVerification.where(dslogon_uuid: user_uuid))
                  .where.not(user_account_id:)
end

#handle_validation_error(e) ⇒ Object (private)



496
497
498
499
500
501
502
# File 'app/models/form526_submission.rb', line 496

def handle_validation_error(e)
  errors = e.errors if e.respond_to?(:errors)
  detail = errors&.dig(0, :detail)
  status = errors&.dig(0, :status)
  error_msg = "#{detail || e} -- #{e.backtrace[0]}"
  mock_lighthouse_response(status:, error: error_msg)
end

#in_process?Boolean

Returns:

  • (Boolean)


450
451
452
# File 'app/models/form526_submission.rb', line 450

def in_process?
  self.class.in_process.exists?(id:)
end

#invalidate_form_hashObject

Call this method to invalidate the memoized @form_hash variable after updating form_json. A hook that calls this method could be added so that we don’t have to call this manually, see stackoverflow.com/questions/24314584/run-a-callback-only-if-an-attribute-has-changed-in-rails



186
187
188
# File 'app/models/form526_submission.rb', line 186

def invalidate_form_hash
  remove_instance_variable(:@form_hash) if instance_variable_defined?(:@form_hash)
end

#jobs_succeeded?Boolean

Returns:

  • (Boolean)


291
292
293
# File 'app/models/form526_submission.rb', line 291

def jobs_succeeded?
  a_submit_form_526_job_succeeded? && all_other_jobs_succeeded_if_any?
end

#last_remediationObject



454
455
456
# File 'app/models/form526_submission.rb', line 454

def last_remediation
  form526_submission_remediations&.order(:created_at)&.last
end

#lighthouse_serviceObject (private)

Setup the Lighthouse service for this user account. Lighthouse calls the user_account.icn the “ID of Veteran”



492
493
494
# File 'app/models/form526_submission.rb', line 492

def lighthouse_service
  BenefitsClaims::Service.new(.icn)
end

#lighthouse_validation_errorsObject

Returns an Array of Hashes when response.status is 422 otherwise it’s an empty Array.

The Array#empty? is true when there are no errors A Hash entry looks like this … {

"title": "Unprocessable entity",
"detail": "The property / did not contain the required key serviceInformation",
"status": "422",
"source": {
  "pointer": "data/attributes/"
}

}



426
427
428
429
430
431
432
# File 'app/models/form526_submission.rb', line 426

def lighthouse_validation_errors
  if lighthouse_validation_response&.status == 200
    []
  else
    lighthouse_validation_response.body['errors']
  end
end

#mark_birls_id_as_tried(id = birls_id!, , timestamp_string: Time.zone.now.iso8601.to_s) ⇒ Object



245
246
247
248
249
250
251
# File 'app/models/form526_submission.rb', line 245

def mark_birls_id_as_tried(id = birls_id!, timestamp_string: Time.zone.now.iso8601.to_s)
  ids = add_birls_ids id
  hash = birls_ids_tried_hash
  hash[ids.first] << timestamp_string
  self.birls_ids_tried = hash.to_json
  timestamp_string
end

#mark_birls_id_as_tried!Object



253
254
255
256
257
# File 'app/models/form526_submission.rb', line 253

def mark_birls_id_as_tried!(*, **)
  timestamp_string = mark_birls_id_as_tried(*, **)
  save!
  timestamp_string
end

#mock_lighthouse_response(status:, error: 'Unknown') ⇒ Object (private)



504
505
506
507
508
509
510
511
512
513
514
515
516
517
# File 'app/models/form526_submission.rb', line 504

def mock_lighthouse_response(status:, error: 'Unknown')
  response_struct = Struct.new(:status, :body)
  mock_response = response_struct.new(status || 609, nil)

  mock_response.body = {
    'errors' => [
      {
        'title' => "Response Status Code '#{mock_response.status}' - #{error}"
      }
    ]
  }

  @lighthouse_validation_response = mock_response
end

#perform_ancillary_jobs(first_name) ⇒ String

Creates a batch for the ancillary jobs, sets up the callback, and adds the jobs to the batch if necessary

Parameters:

  • first_name (String)

    the first name of the user that submitted Form526

Returns:

  • (String)

    the workflow batch id



316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
# File 'app/models/form526_submission.rb', line 316

def perform_ancillary_jobs(first_name)
  workflow_batch = Sidekiq::Batch.new
  workflow_batch.on(
    :success,
    'Form526Submission#workflow_complete_handler',
    'submission_id' => id,
    'first_name' => first_name
  )
  workflow_batch.jobs do
    submit_uploads if form[FORM_526_UPLOADS].present?
    conditionally_submit_form_4142
    submit_form_0781 if form[FORM_0781].present?
    submit_form_8940 if form[FORM_8940].present?
    upload_bdd_instructions if bdd?
    submit_flashes if form[FLASHES].present?
    poll_form526_pdf if Flipper.enabled?(:disability_526_toxic_exposure_document_upload_polling,
                                         OpenStruct.new({ flipper_id: user_uuid }))
    cleanup
  end
end

#perform_ancillary_jobs_handler(_status, options) ⇒ Object

Called by Sidekiq::Batch as part of the Form 526 submission workflow The workflow batch success handler

Parameters:

  • _status (Sidekiq::Batch::Status)

    the status of the batch

  • options (Hash)

    payload set in the workflow batch



285
286
287
288
289
# File 'app/models/form526_submission.rb', line 285

def perform_ancillary_jobs_handler(_status, options)
  submission = Form526Submission.find(options['submission_id'])
  # Only run ancillary jobs if submission succeeded
  submission.perform_ancillary_jobs(options['first_name']) if submission.jobs_succeeded?
end

#personalization_parameters(first_name) ⇒ Object



365
366
367
368
369
370
371
372
373
# File 'app/models/form526_submission.rb', line 365

def personalization_parameters(first_name)
  {
    'email' => form['form526']['form526']['veteran']['emailAddress'],
    'submitted_claim_id' => ,
    'date_submitted' => created_at.strftime('%B %-d, %Y %-l:%M %P %Z').sub(/([ap])m/, '\1.m.'),
    'date_received' => Time.now.utc.strftime('%B %-d, %Y %-l:%M %P %Z').sub(/([ap])m/, '\1.m.'),
    'first_name' => first_name
  }
end

#poll_form526_pdfObject (private)



582
583
584
585
586
587
588
# File 'app/models/form526_submission.rb', line 582

def poll_form526_pdf
  # In order to track the status of the 526 PDF upload via Lighthouse,
  # call poll_form526_pdf, provided we received a valid claim_id from Lighthouse
  if saved_claim.parsed_form['startedFormVersion'].present? && 
    Lighthouse::PollForm526Pdf.perform_async(id)
  end
end

#queue_central_mail_backup_submission_for_non_retryable_error!(e: nil) ⇒ Object (private)



519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
# File 'app/models/form526_submission.rb', line 519

def queue_central_mail_backup_submission_for_non_retryable_error!(e: nil)
  # Entry-point for backup 526 CMP submission
  #
  # Required criteria to send a backup 526 submission from here:
  # Enabled in settings and flipper
  # Does not have a valid claim ID (through RRD process or otherwise) (protect against dup submissions)
  # Does not have a backup submission ID (protect against dup submissions)
  backup_job_jid = nil
  flipper_sym = :form526_backup_submission_temp_killswitch
  send_backup_submission = Settings.form526_backup.enabled &&
                           Flipper.enabled?(flipper_sym) &&
                           .nil? &&
                           .nil?

  backup_job_jid = enqueue_backup_submission(id) if send_backup_submission

  log_message = {
    submission_id: id
  }
  log_message['error_class']   = e.class unless e.nil?
  log_message['error_message'] = e.message unless e.nil?
  log_message['backup_job_id'] = backup_job_jid unless backup_job_jid.nil?
  ::Rails.logger.error('Form526 Exhausted or Errored (non-retryable-error-path)', log_message)
end

#remediated?Boolean

Returns:

  • (Boolean)


438
439
440
# File 'app/models/form526_submission.rb', line 438

def remediated?
  last_remediation&.success || false
end

#startObject

Called when the DisabilityCompensation form controller is ready to hand off to the backend submission process. Currently this passes directly to the retryable EVSS workflow, but if any one-time setup or workflow redirection (e.g. for Claims Fast-Tracking) needs to happen, it should go here and call start_evss_submission_job when done.



94
95
96
97
# File 'app/models/form526_submission.rb', line 94

def start
  log_max_cfi_metrics_on_submit
  start_evss_submission_job
end

#start_evss_submission_jobString

Kicks off a retryable 526 submit workflow. The first step in a submission workflow is to submit an increase only or all claims form. Once the first job succeeds the batch will callback and run one (cleanup job) or more ancillary jobs such as uploading supporting evidence or submitting ancillary forms.

Returns:

  • (String)

    the job id of the first job in the batch, i.e the 526 submit job



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'app/models/form526_submission.rb', line 105

def start_evss_submission_job
  workflow_batch = Sidekiq::Batch.new
  workflow_batch.on(
    :success,
    'Form526Submission#perform_ancillary_jobs_handler',
    'submission_id' => id,
    # Call get_first_name while the temporary User record still exists
    'first_name' => get_first_name
  )
  job_ids = workflow_batch.jobs do
    EVSS::DisabilityCompensationForm::SubmitForm526AllClaim.perform_async(id)
  end

  job_ids.first
end

#submit_flashesObject (private)



575
576
577
578
579
580
# File 'app/models/form526_submission.rb', line 575

def submit_flashes
  user = User.find(user_uuid)
  # Note that the User record is cached in Redis -- `User.redis_namespace_ttl`
  # If this method runs after the TTL, then the flashes will not be applied -- a possible bug.
  BGS::FlashUpdater.perform_async(id) if user && Flipper.enabled?(:disability_compensation_flashes, user)
end

#submit_form_0781Object (private)



567
568
569
# File 'app/models/form526_submission.rb', line 567

def submit_form_0781
  EVSS::DisabilityCompensationForm::SubmitForm0781.perform_async(id)
end

#submit_form_4142Object (private)



563
564
565
# File 'app/models/form526_submission.rb', line 563

def submit_form_4142
  CentralMail::SubmitForm4142Job.perform_async(id)
end

#submit_form_8940Object (private)



571
572
573
# File 'app/models/form526_submission.rb', line 571

def submit_form_8940
  EVSS::DisabilityCompensationForm::SubmitForm8940.perform_async(id)
end

#submit_uploadsObject (private)



548
549
550
551
552
553
554
555
556
# File 'app/models/form526_submission.rb', line 548

def submit_uploads
  # Put uploads on a one minute delay because of shared workload with EVSS
  uploads = form[FORM_526_UPLOADS]
  delay = 60.seconds
  uploads.each do |upload|
    EVSS::DisabilityCompensationForm::SubmitUploads.perform_in(delay, id, upload)
    delay += 15.seconds
  end
end

#submit_with_birls_id_that_hasnt_been_tried_yet!(extra_content_for_sentry: {}, silence_errors_and_log_to_sentry: false) ⇒ String, NilClass

Runs start_evss_submission_job but first looks to see if the veteran has BIRLS IDs that previous start attempts haven’t used before (if so, swaps one of those into auth_headers). If all BIRLS IDs for a veteran have been tried, does nothing and returns nil. Note: this assumes that the current BIRLS ID has been used (that ‘start` has been attempted once).

Returns:

  • (String)

    the job id of the first job in the batch, i.e the 526 submit job

  • (NilClass)

    all BIRLS IDs for the veteran have been tried



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'app/models/form526_submission.rb', line 129

def submit_with_birls_id_that_hasnt_been_tried_yet!(
  extra_content_for_sentry: {},
  silence_errors_and_log_to_sentry: false
)
  untried_birls_id = birls_ids_that_havent_been_tried_yet.first

  return unless untried_birls_id

  self.birls_id = untried_birls_id
  save!
  start_evss_submission_job
rescue => e
  # 1) why have the 'silence_errors_and_log_to_sentry' option? (why not rethrow the error?)
  # This method is primarily intended to be triggered by a running Sidekiq job that has hit a dead end
  # (exhausted, or non-retryable error). One of the places this method is called is inside a
  # `sidekiq_retries_exhausted` block. It seems like the value of self for that block won't be the
  # Sidekiq job instance (so no access to the log_exception_to_sentry method). Also, rethrowing the error
  # (and letting it bubble up to Sidekiq) might trigger the current job to retry (which we don't want).
  raise unless silence_errors_and_log_to_sentry

  log_exception_to_sentry e, extra_content_for_sentry
end

#success_type?Boolean

Returns:

  • (Boolean)


446
447
448
# File 'app/models/form526_submission.rb', line 446

def success_type?
  self.class.success_type.exists?(id:)
end

#system_transaction_idObject

used to track in APMs between systems such as Lighthouse example: can be used as a search parameter in Datadog TODO: follow-up in ticket #93563 to make this more robust, i.e. attempts of jobs, etc.



85
86
87
88
# File 'app/models/form526_submission.rb', line 85

def system_transaction_id
  service_provider = saved_claim.parsed_form['startedFormVersion'].present? ? 'lighthouse' : 'evss'
  "Form526Submission_#{id}, user_uuid: #{user_uuid}, service_provider: #{service_provider}"
end

#upload_bdd_instructionsObject (private)



558
559
560
561
# File 'app/models/form526_submission.rb', line 558

def upload_bdd_instructions
  # send BDD instructions
  EVSS::DisabilityCompensationForm::UploadBddInstructions.perform_in(60.seconds, id)
end

#veteran_email_addressObject



375
376
377
# File 'app/models/form526_submission.rb', line 375

def veteran_email_address
  form.dig('form526', 'form526', 'veteran', 'emailAddress')
end

#workflow_complete_handler(_status, options) ⇒ Object

Called by Sidekiq::Batch as part of the Form 526 submission workflow Checks if all workflow steps were successful and if so marks it as complete.

Parameters:

  • _status (Sidekiq::Batch::Status)

    the status of the batch

  • options (Hash)

    payload set in the workflow batch



343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'app/models/form526_submission.rb', line 343

def workflow_complete_handler(_status, options)
  submission = Form526Submission.find(options['submission_id'])
  params = submission.personalization_parameters(options['first_name'])
  if submission.jobs_succeeded?
    # If the received_email_from_polling feature enabled, skip this call
    unless Flipper.enabled?(:disability_526_call_received_email_from_polling,
                            OpenStruct.new({ flipper_id: user_uuid }))
      Rails.logger.info("Form526ConfirmationEmailJob called for user: #{user_uuid},
                                            submission: #{submission.id} from form526_submission")
      Form526ConfirmationEmailJob.perform_async(params)
    end
    submission.workflow_complete = true
    submission.save
  else
    Form526SubmissionFailedEmailJob.perform_async(params)
  end
end