From 02ff64f3d2e147671d21222461ecf2f3fd43cbd0 Mon Sep 17 00:00:00 2001 From: mchristiansonVA <95487885+mchristiansonVA@users.noreply.github.com> Date: Mon, 25 Mar 2024 09:07:59 -0400 Subject: [PATCH] Api 34592 poa v2 claimant signatures (#15827) * Schema updates and add generated swagger * Add logic to use veteran or claimant for sig, update tests * Add tests for non-veteran claimants * Rubocop fixes * Remove unused attribute from tests * POA v2: Clean up required attributes * Validate claimantId included when request includes claimant data * Add test, fix logic based on tests * Add test for org request * Rubocop to the rescue * Update test data to reflect schema updates * Compiles swagger docs with update changes to required/not required values * Fixing Gemfile.lock after merge conflict * Adds space at the end of Gemfile.lock file * Update modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_validation.rb Co-authored-by: jvcAdHoc <144135615+jvcAdHoc@users.noreply.github.com> * Cleans up a conditional and spelling error * Adds language to explain conditionally required fields in schemas/docs * Move logic to validation class, add to errors if found * Validate claimantId, handle MPI errors, handle missing claimantId in form builder * Update error message and add cassette * Refactor logic to single call to MPI * Fix poa individual request tests * Disable module length check on poa validation * Refactor to use form_data to store claimant first & last * Fix tests, misc cleanup * Refactor user profile access * Rename variables to differ from method name * Add defined? check for to handle nil from mpi --------- Co-authored-by: Derrick Ellerbie Co-authored-by: rockwellwindsor-va Co-authored-by: Rockwell Windsor Rice <129893414+rockwellwindsor-va@users.noreply.github.com> Co-authored-by: jvcAdHoc <144135615+jvcAdHoc@users.noreply.github.com> --- .../power_of_attorney/base_controller.rb | 27 +- .../v2/power_of_attorney_validation.rb | 30 +- .../claims_api/v2/poa_form_builder_job.rb | 32 +- .../swagger/claims_api/v2/dev/swagger.json | 70 +--- .../claims_api/config/schemas/v2/2122.json | 16 +- .../claims_api/config/schemas/v2/2122a.json | 19 +- .../power_of_attorney_ind_request_spec.rb | 115 +++++-- .../power_of_attorney_org_request_spec.rb | 41 +++ .../sidekiq/v2/poa_form_builder_job_spec.rb | 324 +++++++++++++++--- 9 files changed, 483 insertions(+), 191 deletions(-) diff --git a/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/base_controller.rb b/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/base_controller.rb index 784253396d7..519ea0a5552 100644 --- a/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/base_controller.rb +++ b/modules/claims_api/app/controllers/claims_api/v2/veterans/power_of_attorney/base_controller.rb @@ -46,9 +46,10 @@ def request_representative def shared_form_validation(form_number) target_veteran # Custom validations for POA submission, we must check this first - @claims_api_forms_validation_errors = validate_form_2122_and_2122a_submission_values + @claims_api_forms_validation_errors = validate_form_2122_and_2122a_submission_values(user_profile) # JSON validations for POA submission, will combine with previously captured errors and raise validate_json_schema(form_number.upcase) + add_claimant_data_to_form if user_profile # if we get here there were only validations file errors if @claims_api_forms_validation_errors raise ::ClaimsApi::Common::Exceptions::Lighthouse::JsonDisabilityCompensationValidationError, @@ -167,6 +168,30 @@ def nullable_icn nil end + + def user_profile + return @user_profile if defined? @user_profile + + @user_profile ||= fetch_claimant + end + + def fetch_claimant + claimant_icn = form_attributes.dig('claimant', 'claimantId') + if claimant_icn.present? + mpi_profile = mpi_service.find_profile_by_identifier(identifier: claimant_icn, + identifier_type: MPI::Constants::ICN) + end + rescue ArgumentError + mpi_profile + end + + def add_claimant_data_to_form + if user_profile&.status == :ok + first_name = user_profile.profile.given_names.first + last_name = user_profile.profile.family_name + form_attributes['claimant'].merge!(firstName: first_name, lastName: last_name) + end + end end end end diff --git a/modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_validation.rb b/modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_validation.rb index b535ff11709..c1001eb50b0 100644 --- a/modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_validation.rb +++ b/modules/claims_api/app/controllers/concerns/claims_api/v2/power_of_attorney_validation.rb @@ -1,19 +1,22 @@ # frozen_string_literal: false +# rubocop:disable Metrics/ModuleLength + module ClaimsApi module V2 module PowerOfAttorneyValidation - def validate_form_2122_and_2122a_submission_values - validate_claimant + def validate_form_2122_and_2122a_submission_values(user_profile) + validate_claimant(user_profile) # collect errors and pass back to the controller raise_error_collection if @errors end private - def validate_claimant + def validate_claimant(user_profile) return if form_attributes['claimant'].blank? + validate_claimant_id_included(user_profile) validate_address validate_relationship end @@ -92,6 +95,26 @@ def validate_relationship end end + def validate_claimant_id_included(user_profile) + claimant_icn = form_attributes.dig('claimant', 'claimantId') + if (user_profile.blank? || user_profile&.status == :not_found) && claimant_icn + collect_error_messages( + source: 'claimant/claimantId', + detail: "The 'claimantId' must be valid" + ) + else + address = form_attributes.dig('claimant', 'address') + phone = form_attributes.dig('claimant', 'phone') + relationship = form_attributes.dig('claimant', 'relationship') + return if claimant_icn.present? && (address.present? || phone.present? || relationship.present?) + + collect_error_messages( + source: '/claimant/claimantId/', + detail: "If claimant is present 'claimantId' must be filled in" + ) + end + end + def errors_array @errors ||= [] end @@ -109,3 +132,4 @@ def raise_error_collection end end end +# rubocop:enable Metrics/ModuleLength diff --git a/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb b/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb index 0517d611694..45067e86e59 100644 --- a/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb +++ b/modules/claims_api/app/sidekiq/claims_api/v2/poa_form_builder_job.rb @@ -65,18 +65,19 @@ def data(power_of_attorney, form_number) end def organization_signatures(power_of_attorney) - first_name = power_of_attorney.form_data['serviceOrganization']['firstName'] - last_name = power_of_attorney.form_data['serviceOrganization']['lastName'] + rep_first_name = power_of_attorney.form_data['serviceOrganization']['firstName'] + rep_last_name = power_of_attorney.form_data['serviceOrganization']['lastName'] + first_name, last_name = veteran_or_claimant_signature(power_of_attorney) { 'page2' => [ { - 'signature' => "#{power_of_attorney.auth_headers['va_eauth_firstName']} " \ - "#{power_of_attorney.auth_headers['va_eauth_lastName']} - signed via api.va.gov", + 'signature' => "#{first_name} " \ + "#{last_name} - signed via api.va.gov", 'x' => 35, 'y' => 240 }, { - 'signature' => "#{first_name} #{last_name} - signed via api.va.gov", + 'signature' => "#{rep_first_name} #{rep_last_name} - signed via api.va.gov", 'x' => 35, 'y' => 200 } @@ -109,21 +110,34 @@ def individual_page1_signatures(power_of_attorney, first_name, last_name) ] end - def individual_page2_signatures(power_of_attorney, first_name, last_name) + def individual_page2_signatures(power_of_attorney, rep_first_name, rep_last_name) + first_name, last_name = veteran_or_claimant_signature(power_of_attorney) [ { - 'signature' => "#{power_of_attorney.auth_headers['va_eauth_firstName']} " \ - "#{power_of_attorney.auth_headers['va_eauth_lastName']} - signed via api.va.gov", + 'signature' => "#{first_name} " \ + "#{last_name} - signed via api.va.gov", 'x' => 35, 'y' => 306 }, { - 'signature' => "#{first_name} #{last_name} - signed via api.va.gov", + 'signature' => "#{rep_first_name} #{rep_last_name} - signed via api.va.gov", 'x' => 35, 'y' => 200 } ] end + + def veteran_or_claimant_signature(power_of_attorney) + claimant = power_of_attorney.form_data['claimant'].present? + if claimant + first_name = power_of_attorney.form_data['claimant']['firstName'] + last_name = power_of_attorney.form_data['claimant']['lastName'] + else + first_name = power_of_attorney.auth_headers['va_eauth_firstName'] + last_name = power_of_attorney.auth_headers['va_eauth_lastName'] + end + [first_name, last_name] + end end end end diff --git a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json index b8b42e0fc36..45d2acf2493 100644 --- a/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json +++ b/modules/claims_api/app/swagger/claims_api/v2/dev/swagger.json @@ -9022,23 +9022,10 @@ "type": "object", "additionalProperties": false, "properties": { - "firstName": { - "description": "First name of Claimant.", - "type": "string", - "example": "John", - "maxLength": 12 - }, - "middleInitial": { - "description": "Middle initial of Claimant.", + "claimantId": { "type": "string", - "example": "M", - "maxLength": 1 - }, - "lastName": { - "description": "Last name of Claimant.", - "type": "string", - "example": "Dow", - "maxLength": 18 + "example": "123456789", + "description": "Id of the claimant." }, "address": { "type": "object", @@ -9716,20 +9703,10 @@ "type": "object", "additionalProperties": false, "properties": { - "firstName": { - "description": "First name of Claimant.", - "type": "string", - "example": "John" - }, - "middleInitial": { - "description": "Middle initial of Claimant.", - "type": "string", - "example": "M" - }, - "lastName": { - "description": "Last name of Claimant.", + "claimantId": { "type": "string", - "example": "Dow" + "example": "123456789", + "description": "Id of the claimant." }, "address": { "type": "object", @@ -10359,23 +10336,10 @@ "type": "object", "additionalProperties": false, "properties": { - "firstName": { - "description": "First name of Claimant.", - "type": "string", - "example": "John", - "maxLength": 12 - }, - "middleInitial": { - "description": "Middle initial of Claimant.", + "claimantId": { "type": "string", - "example": "M", - "maxLength": 1 - }, - "lastName": { - "description": "Last name of Claimant.", - "type": "string", - "example": "Dow", - "maxLength": 18 + "example": "123456789", + "description": "Id of the claimant." }, "address": { "type": "object", @@ -11044,20 +11008,10 @@ "type": "object", "additionalProperties": false, "properties": { - "firstName": { - "description": "First name of Claimant.", - "type": "string", - "example": "John" - }, - "middleInitial": { - "description": "Middle initial of Claimant.", - "type": "string", - "example": "M" - }, - "lastName": { - "description": "Last name of Claimant.", + "claimantId": { "type": "string", - "example": "Dow" + "example": "123456789", + "description": "Id of the claimant." }, "address": { "type": "object", diff --git a/modules/claims_api/config/schemas/v2/2122.json b/modules/claims_api/config/schemas/v2/2122.json index 79f8511c99b..543686f5c4c 100644 --- a/modules/claims_api/config/schemas/v2/2122.json +++ b/modules/claims_api/config/schemas/v2/2122.json @@ -112,20 +112,10 @@ "type": "object", "additionalProperties": false, "properties": { - "firstName": { - "description": "First name of Claimant.", - "type": "string", - "example": "John" - }, - "middleInitial": { - "description": "Middle initial of Claimant.", - "type": "string", - "example": "M" - }, - "lastName": { - "description": "Last name of Claimant.", + "claimantId": { "type": "string", - "example": "Dow" + "example": "123456789", + "description": "Id of the claimant." }, "address": { "type": "object", diff --git a/modules/claims_api/config/schemas/v2/2122a.json b/modules/claims_api/config/schemas/v2/2122a.json index 6a90f806fd4..48d66dfa061 100644 --- a/modules/claims_api/config/schemas/v2/2122a.json +++ b/modules/claims_api/config/schemas/v2/2122a.json @@ -128,23 +128,10 @@ "type": "object", "additionalProperties": false, "properties": { - "firstName": { - "description": "First name of Claimant.", - "type": "string", - "example": "John", - "maxLength": 12 - }, - "middleInitial": { - "description": "Middle initial of Claimant.", - "type": "string", - "example": "M", - "maxLength": 1 - }, - "lastName": { - "description": "Last name of Claimant.", + "claimantId": { "type": "string", - "example": "Dow", - "maxLength": 18 + "example": "123456789", + "description": "Id of the claimant." }, "address": { "type": "object", diff --git a/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_ind_request_spec.rb b/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_ind_request_spec.rb index 95c25dcb5fa..591c9a7f414 100644 --- a/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_ind_request_spec.rb +++ b/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_ind_request_spec.rb @@ -81,8 +81,7 @@ } }, claimant: { - firstName: 'first', - lastName: 'last', + claimantId: '1013062086V794840', address: { addressLine1: '123', city: 'city', @@ -112,15 +111,16 @@ context 'when provided' do context 'when valid' do it 'returns a 202' do - mock_ccg(scopes) do |auth_header| - expect_any_instance_of(local_bgs).to receive(:find_poa_by_participant_id) - .and_return(bgs_poa) - allow_any_instance_of(local_bgs).to receive(:find_poa_history_by_ptcpnt_id) - .and_return({ person_poa_history: nil }) - - post appoint_individual_path, params: data.to_json, headers: auth_header + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + mock_ccg(scopes) do |auth_header| + expect_any_instance_of(local_bgs).to receive(:find_poa_by_participant_id) + .and_return(bgs_poa) + allow_any_instance_of(local_bgs).to receive(:find_poa_history_by_ptcpnt_id) + .and_return({ person_poa_history: nil }) - expect(response).to have_http_status(:accepted) + post appoint_individual_path, params: data.to_json, headers: auth_header + expect(response).to have_http_status(:accepted) + end end end end @@ -147,8 +147,9 @@ it 'returns a 202 when all conditionally required data is present' do mock_ccg(scopes) do |auth_header| - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + end expect(response).to have_http_status(:accepted) end end @@ -156,9 +157,9 @@ it 'returns a 422 if claimant.address.addressLine1 is not provided' do mock_ccg(scopes) do |auth_header| claimant_data[:data][:attributes][:claimant][:address][:addressLine1] = nil - - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + end expect(response).to have_http_status(:unprocessable_entity) response_body = JSON.parse(response.body) expect(response_body['errors'][0]['detail']).to eq( @@ -170,9 +171,9 @@ it 'returns a 422 if claimant.address.city is not provided' do mock_ccg(scopes) do |auth_header| claimant_data[:data][:attributes][:claimant][:address][:city] = nil - - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + end expect(response).to have_http_status(:unprocessable_entity) response_body = JSON.parse(response.body) expect(response_body['errors'][0]['detail']).to eq( @@ -184,9 +185,9 @@ it 'returns a 422 if claimant.address.stateCode is not provided' do mock_ccg(scopes) do |auth_header| claimant_data[:data][:attributes][:claimant][:address][:stateCode] = nil - - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + end expect(response).to have_http_status(:unprocessable_entity) response_body = JSON.parse(response.body) expect(response_body['errors'][0]['detail']).to eq( @@ -198,9 +199,9 @@ it 'returns a 422 if claimant.address.country is not provided' do mock_ccg(scopes) do |auth_header| claimant_data[:data][:attributes][:claimant][:address][:country] = nil - - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + end expect(response).to have_http_status(:unprocessable_entity) response_body = JSON.parse(response.body) expect(response_body['errors'][0]['detail']).to eq( @@ -212,9 +213,9 @@ it 'returns a 422 if claimant.address.zipCode is not provided' do mock_ccg(scopes) do |auth_header| claimant_data[:data][:attributes][:claimant][:address][:zipCode] = nil - - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + end expect(response).to have_http_status(:unprocessable_entity) response_body = JSON.parse(response.body) expect(response_body['errors'][0]['detail']).to eq( @@ -224,16 +225,17 @@ end it 'returns a 422 if claimant.relationship is not provided' do - mock_ccg(scopes) do |auth_header| - claimant_data[:data][:attributes][:claimant][:relationship] = nil - - post appoint_individual_path, params: claimant_data.to_json, headers: auth_header - - expect(response).to have_http_status(:unprocessable_entity) - response_body = JSON.parse(response.body) - expect(response_body['errors'][0]['detail']).to eq( - "If claimant is present 'relationship' must be filled in" - ) + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + mock_ccg(scopes) do |auth_header| + claimant_data[:data][:attributes][:claimant][:relationship] = nil + + post appoint_individual_path, params: claimant_data.to_json, headers: auth_header + expect(response).to have_http_status(:unprocessable_entity) + response_body = JSON.parse(response.body) + expect(response_body['errors'][0]['detail']).to eq( + "If claimant is present 'relationship' must be filled in" + ) + end end end end @@ -380,6 +382,45 @@ end end end + + context 'when no claimantId is provided and other claimant data is present' do + let(:request_body) do + Rails.root.join('modules', 'claims_api', 'spec', 'fixtures', 'v2', 'veterans', + 'power_of_attorney', '2122a', 'valid.json').read + end + + let(:claimant) do + { + email: 'lillian@disney.com', + relationship: 'Spouse', + address: { + addressLine1: '2688 S Camino Real', + city: 'Palm Springs', + stateCode: 'CA', + country: 'US', + zipCode: '92264' + }, + phone: { + areaCode: '555', + phoneNumber: '5551337' + } + } + end + let(:error_msg) { "If claimant is present 'claimantId' must be filled in" } + + it 'returns a meaningful 422' do + mock_ccg(%w[claim.write claim.read]) do |auth_header| + json = JSON.parse(request_body) + json['data']['attributes']['claimant'] = claimant + request_body = json.to_json + post validate2122a_path, params: request_body, headers: auth_header + + response_body = JSON.parse(response.body)['errors'][0] + expect(response).to have_http_status(:unprocessable_entity) + expect(response_body['detail']).to eq(error_msg) + end + end + end end end end diff --git a/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_org_request_spec.rb b/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_org_request_spec.rb index 4d90fd57f7d..9e94f75e87b 100644 --- a/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_org_request_spec.rb +++ b/modules/claims_api/spec/requests/v2/veterans/power_of_attorney_org_request_spec.rb @@ -189,6 +189,47 @@ end end end + + context 'when no claimantId is provided and other claimant data is present' do + let(:request_body) do + Rails.root.join('modules', 'claims_api', 'spec', 'fixtures', 'v2', 'veterans', + 'power_of_attorney', '2122', 'valid.json').read + end + + let(:claimant) do + { + email: 'lillian@disney.com', + relationship: 'Spouse', + address: { + addressLine1: '2688 S Camino Real', + city: 'Palm Springs', + stateCode: 'CA', + country: 'US', + zipCode: '92264' + }, + phone: { + areaCode: '555', + phoneNumber: '5551337' + } + } + end + let(:error_msg) { "If claimant is present 'claimantId' must be filled in" } + + it 'returns a meaningful 422' do + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + mock_ccg(%w[claim.write claim.read]) do |auth_header| + json = JSON.parse(request_body) + json['data']['attributes']['claimant'] = claimant + request_body = json.to_json + post validate2122_path, params: request_body, headers: auth_header + + response_body = JSON.parse(response.body)['errors'][0] + expect(response).to have_http_status(:unprocessable_entity) + expect(response_body['detail']).to eq(error_msg) + end + end + end + end end end end diff --git a/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb b/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb index af45a521059..69532e7d682 100644 --- a/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb +++ b/modules/claims_api/spec/sidekiq/v2/poa_form_builder_job_spec.rb @@ -14,7 +14,7 @@ end describe 'generating and uploading the signed pdf' do - context '2122a' do + context '2122a veteran claimant' do before do power_of_attorney.form_data = { recordConsent: true, @@ -34,9 +34,7 @@ } }, claimant: { - firstName: 'Lillian', - middleInitial: 'A', - lastName: 'Disney', + claimantId: '1012830872V584140', email: 'lillian@disney.com', relationship: 'Spouse', address: { @@ -49,7 +47,9 @@ phone: { areaCode: '555', phoneNumber: '5551337' - } + }, + firstName: 'JESSE', + lastName: 'GRAY' }, representative: { poaCode: poa_code.to_s, @@ -69,6 +69,245 @@ power_of_attorney.save end + it 'generates e-signatures correctly for a veteran claimant' do + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + data = power_of_attorney + .form_data + .deep_merge( + { + 'veteran' => { + 'firstName' => power_of_attorney.auth_headers['va_eauth_firstName'], + 'lastName' => power_of_attorney.auth_headers['va_eauth_lastName'], + 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], + 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] + } + } + ) + final_data = data.merge( + { + 'text_signatures' => { + 'page1' => [ + { + 'signature' => 'JESSE GRAY - signed via api.va.gov', + 'x' => 35, + 'y' => 73 + }, + { + 'signature' => 'Bob Representative - signed via api.va.gov', + 'x' => 35, + 'y' => 100 + } + ], + 'page2' => [ + { + 'signature' => 'JESSE GRAY - signed via api.va.gov', + 'x' => 35, + 'y' => 306 + }, + { + 'signature' => 'Bob Representative - signed via api.va.gov', + 'x' => 35, + 'y' => 200 + } + ] + } + } + ) + + allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) + expect_any_instance_of(ClaimsApi::V2::PoaPdfConstructor::Individual) + .to receive(:construct) + .with(final_data, id: power_of_attorney.id) + .and_call_original + + subject.new.perform(power_of_attorney.id, '2122A') + end + end + + it 'Calls the POA updater job upon successful upload to VBMS' do + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + token_response = OpenStruct.new(upload_token: '<{573F054F-E9F7-4BF2-8C66-D43ADA5C62E7}') + document_response = OpenStruct.new(upload_document_response: { + '@new_document_version_ref_id' => '{52300B69-1D6E-43B2-8BEB-67A7C55346A2}', + '@document_series_ref_id' => '{A57EF6CC-2236-467A-BA4F-1FA1EFD4B374}' + }.with_indifferent_access) + + allow_any_instance_of(ClaimsApi::VBMSUploader).to receive(:fetch_upload_token).and_return(token_response) + allow_any_instance_of(ClaimsApi::VBMSUploader).to receive(:upload_document).and_return(document_response) + allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) + + expect(ClaimsApi::PoaUpdater).to receive(:perform_async) + + subject.new.perform(power_of_attorney.id, '2122A') + end + end + end + + context '2122a non-veteran claimant' do + before do + power_of_attorney.form_data = { + recordConsent: true, + consentAddressChange: true, + consentLimits: ['DRUG ABUSE', 'SICKLE CELL'], + veteran: { + serviceBranch: 'ARMY', + address: { + numberAndStreet: '2719 Hyperion Ave', + city: 'Los Angeles', + state: 'CA', + country: 'US', + zipFirstFive: '92264' + }, + phone: { + areaCode: '555', + phoneNumber: '5551337' + } + }, + claimant: { + claimantId: '1012830872V584140', + email: 'lillian@disney.com', + relationship: 'Spouse', + address: { + numberAndStreet: '2688 S Camino Real', + city: 'Palm Springs', + state: 'CA', + country: 'US', + zipFirstFive: '92264' + }, + phone: { + areaCode: '555', + phoneNumber: '5551337' + }, + firstName: 'Mitchell', + lastName: 'Jenkins' + }, + representative: { + poaCode: poa_code.to_s, + type: 'SERVICE ORGANIZATION REPRESENTATIVE', + firstName: 'Bob', + lastName: 'Representative', + organizationName: 'I Help Vets LLC', + address: { + numberAndStreet: '2719 Hyperion Ave', + city: 'Los Angeles', + state: 'CA', + country: 'US', + zipFirstFive: '92264' + } + } + } + power_of_attorney.save + end + + it 'generates e-signatures correctly for a non-veteran claimant' do + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + data = power_of_attorney + .form_data + .deep_merge( + { + 'veteran' => { + 'firstName' => power_of_attorney.auth_headers['va_eauth_firstName'], + 'lastName' => power_of_attorney.auth_headers['va_eauth_lastName'], + 'ssn' => power_of_attorney.auth_headers['va_eauth_pnid'], + 'birthdate' => power_of_attorney.auth_headers['va_eauth_birthdate'] + } + } + ) + final_data = data.merge( + { + 'text_signatures' => { + 'page1' => [ + { + 'signature' => 'JESSE GRAY - signed via api.va.gov', + 'x' => 35, + 'y' => 73 + }, + { + 'signature' => 'Bob Representative - signed via api.va.gov', + 'x' => 35, + 'y' => 100 + } + ], + 'page2' => [ + { + 'signature' => 'Mitchell Jenkins - signed via api.va.gov', + 'x' => 35, + 'y' => 306 + }, + { + 'signature' => 'Bob Representative - signed via api.va.gov', + 'x' => 35, + 'y' => 200 + } + ] + } + } + ) + + allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) + expect_any_instance_of(ClaimsApi::V2::PoaPdfConstructor::Individual) + .to receive(:construct) + .with(final_data, id: power_of_attorney.id) + .and_call_original + + subject.new.perform(power_of_attorney.id, '2122A') + end + end + end + + context '2122 veteran claimant' do + before do + power_of_attorney.form_data = { + recordConsent: true, + consentAddressChange: true, + consentLimits: %w[DRUG_ABUSE SICKLE_CELL], + veteran: { + address: { + numberAndStreet: '2719 Hyperion Ave', + city: 'Los Angeles', + state: 'CA', + country: 'US', + zipFirstFive: '92264' + }, + phone: { + areaCode: '555', + phoneNumber: '5551337' + } + }, + claimant: { + email: 'lillian@disney.com', + relationship: 'Spouse', + address: { + numberAndStreet: '2688 S Camino Real', + city: 'Palm Springs', + state: 'CA', + country: 'US', + zipFirstFive: '92264' + }, + phone: { + areaCode: '555', + phoneNumber: '5551337' + }, + firstName: 'JESSE', + lastName: 'GRAY' + }, + serviceOrganization: { + poaCode: poa_code.to_s, + firstName: 'Bob', + lastName: 'Representative', + organizationName: 'I Help Vets LLC', + address: { + numberAndStreet: '2719 Hyperion Ave', + city: 'Los Angeles', + state: 'CA', + country: 'US', + zipFirstFive: '92264' + } + } + } + power_of_attorney.save + end + it 'generates e-signatures correctly' do data = power_of_attorney .form_data @@ -85,23 +324,11 @@ final_data = data.merge( { 'text_signatures' => { - 'page1' => [ - { - 'signature' => 'JESSE GRAY - signed via api.va.gov', - 'x' => 35, - 'y' => 73 - }, - { - 'signature' => 'Bob Representative - signed via api.va.gov', - 'x' => 35, - 'y' => 100 - } - ], 'page2' => [ { 'signature' => 'JESSE GRAY - signed via api.va.gov', 'x' => 35, - 'y' => 306 + 'y' => 240 }, { 'signature' => 'Bob Representative - signed via api.va.gov', @@ -114,12 +341,14 @@ ) allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) - expect_any_instance_of(ClaimsApi::V2::PoaPdfConstructor::Individual) - .to receive(:construct) - .with(final_data, id: power_of_attorney.id) - .and_call_original + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + expect_any_instance_of(ClaimsApi::V2::PoaPdfConstructor::Organization) + .to receive(:construct) + .with(final_data, id: power_of_attorney.id) + .and_call_original - subject.new.perform(power_of_attorney.id, '2122A') + subject.new.perform(power_of_attorney.id, '2122') + end end it 'Calls the POA updater job upon successful upload to VBMS' do @@ -132,19 +361,20 @@ allow_any_instance_of(ClaimsApi::VBMSUploader).to receive(:fetch_upload_token).and_return(token_response) allow_any_instance_of(ClaimsApi::VBMSUploader).to receive(:upload_document).and_return(document_response) allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + expect(ClaimsApi::PoaUpdater).to receive(:perform_async) - expect(ClaimsApi::PoaUpdater).to receive(:perform_async) - - subject.new.perform(power_of_attorney.id, '2122A') + subject.new.perform(power_of_attorney.id, '2122') + end end end - context '2122' do + context '2122 non-veteran claimant' do before do power_of_attorney.form_data = { recordConsent: true, consentAddressChange: true, - consentLimits: %w[DRUG_ABUSE SICKLE_CELL], + consentLimits: ['DRUG ABUSE', 'SICKLE CELL'], veteran: { address: { numberAndStreet: '2719 Hyperion Ave', @@ -159,9 +389,7 @@ } }, claimant: { - firstName: 'Lillian', - middleInitial: 'A', - lastName: 'Disney', + claimantId: '1012830872V584140', email: 'lillian@disney.com', relationship: 'Spouse', address: { @@ -174,7 +402,9 @@ phone: { areaCode: '555', phoneNumber: '5551337' - } + }, + firstName: 'Mitchell', + lastName: 'Jenkins' }, serviceOrganization: { poaCode: poa_code.to_s, @@ -211,7 +441,7 @@ 'text_signatures' => { 'page2' => [ { - 'signature' => 'JESSE GRAY - signed via api.va.gov', + 'signature' => 'Mitchell Jenkins - signed via api.va.gov', 'x' => 35, 'y' => 240 }, @@ -226,28 +456,14 @@ ) allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) - expect_any_instance_of(ClaimsApi::V2::PoaPdfConstructor::Organization) - .to receive(:construct) - .with(final_data, id: power_of_attorney.id) - .and_call_original - - subject.new.perform(power_of_attorney.id, '2122') - end - - it 'Calls the POA updater job upon successful upload to VBMS' do - token_response = OpenStruct.new(upload_token: '<{573F054F-E9F7-4BF2-8C66-D43ADA5C62E7}') - document_response = OpenStruct.new(upload_document_response: { - '@new_document_version_ref_id' => '{52300B69-1D6E-43B2-8BEB-67A7C55346A2}', - '@document_series_ref_id' => '{A57EF6CC-2236-467A-BA4F-1FA1EFD4B374}' - }.with_indifferent_access) - - allow_any_instance_of(ClaimsApi::VBMSUploader).to receive(:fetch_upload_token).and_return(token_response) - allow_any_instance_of(ClaimsApi::VBMSUploader).to receive(:upload_document).and_return(document_response) - allow_any_instance_of(BGS::PersonWebService).to receive(:find_by_ssn).and_return({ file_nbr: '123456789' }) - - expect(ClaimsApi::PoaUpdater).to receive(:perform_async) + VCR.use_cassette('mpi/find_candidate/valid_icn_full') do + expect_any_instance_of(ClaimsApi::V2::PoaPdfConstructor::Organization) + .to receive(:construct) + .with(final_data, id: power_of_attorney.id) + .and_call_original - subject.new.perform(power_of_attorney.id, '2122') + subject.new.perform(power_of_attorney.id, '2122') + end end end end