Class: DecisionReview::Service

Inherits:
Common::Client::Base show all
Includes:
Common::Client::Concerns::Monitoring, DecisionReviewV1::Appeals::LoggingUtils, SentryLogging
Defined in:
lib/decision_review/service.rb

Overview

Proxy Service for the Lighthouse Decision Reviews API.

Constant Summary collapse

STATSD_KEY_PREFIX =
'api.decision_review'
HLR_CREATE_RESPONSE_SCHEMA =
VetsJsonSchema::SCHEMAS.fetch 'HLR-CREATE-RESPONSE-200'
HLR_SHOW_RESPONSE_SCHEMA =
VetsJsonSchema::SCHEMAS.fetch 'HLR-SHOW-RESPONSE-200'
HLR_GET_CONTESTABLE_ISSUES_RESPONSE_SCHEMA =
VetsJsonSchema::SCHEMAS.fetch 'HLR-GET-CONTESTABLE-ISSUES-RESPONSE-200'
REQUIRED_CREATE_HEADERS =
%w[X-VA-First-Name X-VA-Last-Name X-VA-SSN X-VA-Birth-Date].freeze
NO_ZIP_PLACEHOLDER =
'00000'

Class Method Summary collapse

Instance Method Summary collapse

Methods included from DecisionReviewV1::Appeals::LoggingUtils

#benchmark_to_log_data_hash, #log_formatted, #parse_form412_response_to_log_msg, #parse_lighthouse_response_to_log_msg, #run_and_benchmark_if_enabled

Methods included from Common::Client::Concerns::Monitoring

#with_monitoring

Methods included from SentryLogging

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

Methods inherited from Common::Client::Base

configuration, #raise_backend_exception

Class Method Details

.file_upload_metadata(user) ⇒ Object



235
236
237
238
239
240
241
242
243
244
# File 'lib/decision_review/service.rb', line 235

def self.(user)
  {
    'veteranFirstName' => transliterate_name(user.first_name),
    'veteranLastName' => transliterate_name(user.last_name),
    'zipCode' => user.postal_code || NO_ZIP_PLACEHOLDER,
    'fileNumber' => user.ssn.to_s.strip,
    'source' => 'Vets.gov',
    'businessLine' => 'BVA'
  }.to_json
end

.transliterate_name(str) ⇒ Object

upstream requirements ^[a-zA-Z-/s]1,50$ Cannot be missing or empty or longer than 50 characters. Only upper/lower case letters, hyphens(-), spaces and forward-slash(/) allowed



250
251
252
# File 'lib/decision_review/service.rb', line 250

def self.transliterate_name(str)
  I18n.transliterate(str.to_s).gsub(%r{[^a-zA-Z\-/\s]}, '').strip.first(50)
end

Instance Method Details

#create_higher_level_review(request_body:, user:) ⇒ Faraday::Response

Create a Higher-Level Review

Parameters:

  • request_body (JSON)

    JSON serialized version of a Higher-Level Review Form (20-0996)

  • user (User)

    Veteran who the form is in regard to

Returns:

  • (Faraday::Response)


40
41
42
43
44
45
46
47
48
# File 'lib/decision_review/service.rb', line 40

def create_higher_level_review(request_body:, user:)
  with_monitoring_and_error_handling do
    headers = create_higher_level_review_headers(user)
    response = perform :post, 'higher_level_reviews', request_body, headers
    raise_schema_error_unless_200_status response.status
    validate_against_schema json: response.body, schema: HLR_CREATE_RESPONSE_SCHEMA, append_to_error_class: ' (HLR)'
    response
  end
end

#create_notice_of_disagreement(request_body:, user:) ⇒ Faraday::Response

Create a Notice of Disagreement

Parameters:

  • request_body (JSON)

    JSON serialized version of a Notice of Disagreement Form (10182)

  • user (User)

    Veteran who the form is in regard to

Returns:

  • (Faraday::Response)


57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/decision_review/service.rb', line 57

def create_notice_of_disagreement(request_body:, user:) # rubocop:disable Metrics/MethodLength
  with_monitoring_and_error_handling do
    headers = create_notice_of_disagreement_headers(user)
    common_log_params = {
      key: :overall_claim_submission,
      form_id: '10182',
      user_uuid: user.uuid,
      downstream_system: 'Lighthouse'
    }
    begin
      response = perform :post, 'notice_of_disagreements', request_body, headers
      log_formatted(**common_log_params.merge(is_success: true, status_code: response.status, body: '[Redacted]'))
    rescue => e
      # We can freely log Lighthouse's error responses because they do not include PII or PHI.
      # See https://developer.va.gov/explore/api/decision-reviews/docs?version=v1.
      log_formatted(**common_log_params.merge(is_success: false, response_error: e))
      raise e
    end
    raise_schema_error_unless_200_status response.status
    validate_against_schema(
      json: response.body, schema: Schemas::NOD_CREATE_RESPONSE_200, append_to_error_class: ' (NOD)'
    )
    response
  end
end

#get_higher_level_review(uuid) ⇒ Faraday::Response

Retrieve a Higher-Level Review

Parameters:

  • uuid (uuid)

    A Higher-Level Review’s UUID (included in a create_higher_level_review response)

Returns:

  • (Faraday::Response)


89
90
91
92
93
94
95
96
# File 'lib/decision_review/service.rb', line 89

def get_higher_level_review(uuid)
  with_monitoring_and_error_handling do
    response = perform :get, "higher_level_reviews/#{uuid}", nil
    raise_schema_error_unless_200_status response.status
    validate_against_schema json: response.body, schema: HLR_SHOW_RESPONSE_SCHEMA, append_to_error_class: ' (HLR)'
    response
  end
end

#get_higher_level_review_contestable_issues(user:, benefit_type:) ⇒ Faraday::Response

Get Contestable Issues for a Higher-Level Review

Parameters:

  • user (User)

    Veteran who the form is in regard to

  • benefit_type (String)

    Type of benefit the decision review is for

Returns:

  • (Faraday::Response)


122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/decision_review/service.rb', line 122

def get_higher_level_review_contestable_issues(user:, benefit_type:)
  with_monitoring_and_error_handling do
    path = "higher_level_reviews/contestable_issues/#{benefit_type}"
    headers = get_contestable_issues_headers(user)
    response = perform :get, path, nil, headers
    raise_schema_error_unless_200_status response.status
    validate_against_schema(
      json: response.body,
      schema: HLR_GET_CONTESTABLE_ISSUES_RESPONSE_SCHEMA,
      append_to_error_class: ' (HLR)'
    )
    response
  end
end

#get_notice_of_disagreement(uuid) ⇒ Faraday::Response

Retrieve a Notice of Disagreement

Parameters:

  • uuid (uuid)

    A Notice of Disagreement’s UUID (included in a create_notice_of_disagreement response)

Returns:

  • (Faraday::Response)


104
105
106
107
108
109
110
111
112
113
# File 'lib/decision_review/service.rb', line 104

def get_notice_of_disagreement(uuid)
  with_monitoring_and_error_handling do
    response = perform :get, "notice_of_disagreements/#{uuid}", nil
    raise_schema_error_unless_200_status response.status
    validate_against_schema(
      json: response.body, schema: Schemas::NOD_SHOW_RESPONSE_200, append_to_error_class: ' (NOD)'
    )
    response
  end
end

#get_notice_of_disagreement_contestable_issues(user:) ⇒ Faraday::Response

Get Contestable Issues for a Notice of Disagreement

Parameters:

  • user (User)

    Veteran who the form is in regard to

Returns:

  • (Faraday::Response)


143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/decision_review/service.rb', line 143

def get_notice_of_disagreement_contestable_issues(user:) # rubocop:disable Metrics/MethodLength
  with_monitoring_and_error_handling do
    path = 'notice_of_disagreements/contestable_issues'
    headers = get_contestable_issues_headers(user)
    common_log_params = {
      key: :get_contestable_issues,
      form_id: '10182',
      user_uuid: user.uuid,
      upstream_system: 'Lighthouse'
    }
    begin
      response = perform :get, path, nil, headers
      log_formatted(**common_log_params.merge(is_success: true, status_code: response.status, body: '[Redacted]'))
    rescue => e
      # We can freely log Lighthouse's error responses because they do not include PII or PHI.
      # See https://developer.va.gov/explore/api/decision-reviews/docs?version=v1.
      log_formatted(**common_log_params.merge(is_success: false, response_error: e))
      raise e
    end
    raise_schema_error_unless_200_status response.status
    validate_against_schema(
      json: response.body,
      schema: Schemas::NOD_CONTESTABLE_ISSUES_RESPONSE_200,
      append_to_error_class: ' (NOD)'
    )
    response
  end
end

#get_notice_of_disagreement_upload(guid:) ⇒ Faraday::Response

Returns all of the data associated with a specific Notice of Disagreement Evidence Submission.

Parameters:

  • guid (uuid)

    the uuid returnd from get_notice_of_disagreement_upload_url

Returns:

  • (Faraday::Response)


229
230
231
232
233
# File 'lib/decision_review/service.rb', line 229

def get_notice_of_disagreement_upload(guid:)
  with_monitoring_and_error_handling do
    perform :get, "notice_of_disagreements/evidence_submissions/#{guid}", nil
  end
end

#get_notice_of_disagreement_upload_url(nod_uuid:, ssn:) ⇒ Faraday::Response

Get the url to upload supporting evidence for a Notice of Disagreement

Parameters:

  • nod_uuid (uuid)

    The uuid of the submited Notice of Disagreement

Returns:

  • (Faraday::Response)


179
180
181
182
183
184
# File 'lib/decision_review/service.rb', line 179

def get_notice_of_disagreement_upload_url(nod_uuid:, ssn:)
  with_monitoring_and_error_handling do
    perform :post, 'notice_of_disagreements/evidence_submissions', { nod_uuid: },
            { 'X-VA-SSN' => ssn.to_s.strip.presence }
  end
end

#put_notice_of_disagreement_upload(upload_url:, file_upload:, metadata_string:) ⇒ Faraday::Response

Get the url to upload supporting evidence for a Notice of Disagreement

Parameters:

  • upload_url (String)

    The url for the document to be uploaded

  • file_path (String)

    The file path for the document to be uploaded

  • metadata (Hash)

    additional data

Returns:

  • (Faraday::Response)


196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/decision_review/service.rb', line 196

def put_notice_of_disagreement_upload(upload_url:, file_upload:, metadata_string:)
  content_tmpfile = Tempfile.new(file_upload.filename, encoding: file_upload.read.encoding)
  content_tmpfile.write(file_upload.read)
  content_tmpfile.rewind

  json_tmpfile = Tempfile.new('metadata.json', encoding: 'utf-8')
  json_tmpfile.write()
  json_tmpfile.rewind

  params = { metadata: Faraday::UploadIO.new(json_tmpfile.path, Mime[:json].to_s, 'metadata.json'),
             content: Faraday::UploadIO.new(content_tmpfile.path, Mime[:pdf].to_s, file_upload.filename) }

  # when we upgrade to Faraday >1.0
  # params = { metadata: Faraday::FilePart.new(json_tmpfile, Mime[:json].to_s, 'metadata.json'),
  #            content: Faraday::FilePart.new(content_tmpfile, Mime[:pdf].to_s, file_upload.filename) }
  with_monitoring_and_error_handling do
    perform :put, upload_url, params, { 'Content-Type' => 'multipart/form-data' }
  end
ensure
  content_tmpfile.close
  content_tmpfile.unlink
  json_tmpfile.close
  json_tmpfile.unlink
end