-
Notifications
You must be signed in to change notification settings - Fork 63
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[API-34448] VA Notify - Send declined notification #19362
base: master
Are you sure you want to change the base?
Changes from 15 commits
38f8ea8
8766401
dfd3a2d
717ec72
042e88e
5091dd0
4baf283
4bb5067
d13c042
9535c21
22804a6
1800d14
4953a34
97ccbdb
bc6ef6b
0f00e6b
293f3dd
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,28 +33,27 @@ def index | |
|
||
def decide | ||
proc_id = form_attributes['procId'] | ||
ptcpnt_id = form_attributes['participantId'] | ||
decision = normalize(form_attributes['decision']) | ||
representative_id = form_attributes['representativeId'] | ||
|
||
unless proc_id | ||
raise ::Common::Exceptions::ParameterMissing.new('procId', | ||
detail: 'procId is required') | ||
end | ||
validate_decide_params!(proc_id:, decision:) | ||
|
||
decision = form_attributes['decision'] | ||
service = ManageRepresentativeService.new(external_uid: 'power_of_attorney_request_uid', | ||
external_key: 'power_of_attorney_request_key') | ||
|
||
unless decision && %w[accepted declined].include?(normalize(decision)) | ||
raise ::Common::Exceptions::ParameterMissing.new( | ||
'decision', | ||
detail: 'decision is required and must be either "ACCEPTED" or "DECLINED"' | ||
) | ||
if decision == 'declined' | ||
poa_request = validate_ptcpnt_id!(ptcpnt_id:, proc_id:, representative_id:, service:) | ||
end | ||
|
||
service = ManageRepresentativeService.new(external_uid: 'power_of_attorney_request_uid', | ||
external_key: 'power_of_attorney_request_key') | ||
first_name = poa_request['claimantFirstName'] || poa_request['vetFirstName'].presence if poa_request | ||
|
||
res = service.update_poa_request(proc_id:, secondary_status: decision, | ||
declined_reason: form_attributes['declinedReason']) | ||
|
||
raise ::Common::Exceptions::Lighthouse::BadGateway unless res | ||
raise Common::Exceptions::Lighthouse::BadGateway if res.blank? | ||
|
||
send_declined_notification(ptcpnt_id:, first_name:, representative_id:) if decision == 'declined' | ||
|
||
render json: res, status: :ok | ||
end | ||
|
@@ -94,6 +93,53 @@ def create | |
|
||
private | ||
|
||
def validate_decide_params!(proc_id:, decision:) | ||
if proc_id.blank? | ||
raise ::Common::Exceptions::ParameterMissing.new('procId', | ||
detail: 'procId is required') | ||
tycol7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
unless decision.present? && %w[accepted declined].include?(decision) | ||
raise ::Common::Exceptions::ParameterMissing.new( | ||
'decision', | ||
detail: 'decision is required and must be either "ACCEPTED" or "DECLINED"' | ||
) | ||
tycol7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
end | ||
|
||
def send_declined_notification(ptcpnt_id:, first_name:, representative_id:) | ||
lockbox = Lockbox.new(key: Settings.lockbox.master_key) | ||
encrypted_ptcpnt_id = Base64.strict_encode64(lockbox.encrypt(ptcpnt_id)) | ||
encrypted_first_name = Base64.strict_encode64(lockbox.encrypt(first_name)) | ||
|
||
ClaimsApi::VANotifyDeclinedJob.perform_async(encrypted_ptcpnt_id, encrypted_first_name, representative_id) | ||
end | ||
|
||
def validate_ptcpnt_id!(ptcpnt_id:, proc_id:, representative_id:, service:) | ||
if ptcpnt_id.blank? | ||
raise ::Common::Exceptions::ParameterMissing.new('ptcpntId', | ||
detail: 'ptcpntId is required if decision is declined') | ||
end | ||
|
||
if representative_id.blank? | ||
raise ::Common::Exceptions::ParameterMissing | ||
.new('representativeId', detail: 'representativeId is required if decision is declined') | ||
end | ||
|
||
res = service.read_poa_request_by_ptcpnt_id(ptcpnt_id:) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. meaning we could also make this call in the job so we don't have to send first name and poa code to the decline job? https://github.com/department-of-veterans-affairs/vets-api/pull/19362/files#r1842665735 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, I think the fewer dependencies on BGS the better. |
||
|
||
raise ::Common::Exceptions::Lighthouse::BadGateway if res.blank? | ||
|
||
poa_requests = Array.wrap(res['poaRequestRespondReturnVOList']) | ||
|
||
matching_request = poa_requests.find { |poa_request| poa_request['procID'] == proc_id } | ||
|
||
detail = 'Participant ID/Process ID combination not found' | ||
raise ::Common::Exceptions::ResourceNotFound.new(detail:) if matching_request.nil? | ||
|
||
matching_request | ||
end | ||
|
||
def validate_accredited_representative(registration_number, poa_code) | ||
@representative = ::Veteran::Service::Representative.where('? = ANY(poa_codes) AND representative_id = ?', | ||
poa_code, | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
# frozen_string_literal: true | ||
|
||
module ClaimsApi | ||
class VANotifyDeclinedJob < ClaimsApi::ServiceBase | ||
LOG_TAG = 'va_notify_declined_job' | ||
|
||
def perform(encrypted_ptcpnt_id, encrypted_first_name, representative_id) | ||
lockbox = Lockbox.new(key: Settings.lockbox.master_key) | ||
ptcpnt_id = lockbox.decrypt(Base64.strict_decode64(encrypted_ptcpnt_id)) | ||
first_name = lockbox.decrypt(Base64.strict_decode64(encrypted_first_name)) | ||
representative = ::Veteran::Service::Representative.find_by(representative_id:) | ||
|
||
if representative.blank? | ||
raise ClaimsApi::Common::Exceptions::Lighthouse::ResourceNotFound.new( | ||
detail: "Could not find veteran representative with id: #{representative_id}" | ||
) | ||
end | ||
|
||
res = send_declined_notification(ptcpnt_id:, first_name:, representative:) | ||
|
||
ClaimsApi::VANotifyFollowUpJob.perform_async(res.id) if res.present? | ||
rescue => e | ||
msg = "VA Notify email notification failed to send with error #{e}" | ||
slack_alert_on_failure('ClaimsApi::VANotifyDeclinedJob', msg) | ||
|
||
ClaimsApi::Logger.log(LOG_TAG, detail: msg) | ||
|
||
raise e | ||
end | ||
|
||
private | ||
|
||
def find_poa(poa_code:) | ||
ClaimsApi::PowerOfAttorney.find do |poa| | ||
poa.form_data.dig('serviceOrganization', 'poaCode') == poa_code || | ||
poa.form_data.dig('representative', 'poaCode') == poa_code | ||
end | ||
tycol7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
end | ||
|
||
def send_declined_notification(ptcpnt_id:, first_name:, representative:) | ||
representative_type = representative.user_type | ||
return send_organization_notification(ptcpnt_id:, first_name:) if representative_type == 'veteran_service_officer' | ||
|
||
send_representative_notification(ptcpnt_id:, first_name:, representative_type:) | ||
end | ||
|
||
def send_organization_notification(ptcpnt_id:, first_name:) | ||
content = { | ||
recipient_identifier: ptcpnt_id, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Per comment, participant id can be used to send emails. If testing locally, change this line to |
||
personalisation: { | ||
first_name: first_name || '', | ||
form_type: 'Appointment of Veterans Service Organization as Claimantʼs Representative (VA Form 21-22)' | ||
}, | ||
template_id: Settings.claims_api.vanotify.declined_service_organization_template_id | ||
} | ||
|
||
vanotify_service.send_email(content) | ||
end | ||
|
||
def send_representative_notification(ptcpnt_id:, first_name:, representative_type:) | ||
representative_type_text = get_representative_type_text(representative_type:) | ||
|
||
content = { | ||
recipient_identifier: ptcpnt_id, | ||
personalisation: { | ||
first_name: first_name || '', | ||
representative_type: representative_type_text, | ||
representative_type_abbreviated: representative_type_text, | ||
tycol7 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
form_type: 'Appointment of Individual as Claimantʼs Representative (VA Form 21-22a)' | ||
}, | ||
template_id: Settings.claims_api.vanotify.declined_representative_template_id | ||
} | ||
|
||
vanotify_service.send_email(content) | ||
end | ||
|
||
def get_representative_type_text(representative_type:) | ||
case representative_type | ||
when 'attorney' | ||
'attorney' | ||
when 'claim_agents' | ||
'claims agent' | ||
end | ||
end | ||
|
||
def vanotify_service | ||
VaNotify::Service.new(Settings.claims_api.vanotify.services.lighthouse.api_key) | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we need to update these values in prod/AWS?
Also, if testing locally, update these values (found in the ticket) and the VA Notify Lighthouse API key in local settings.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes and we will need to do a manifest update for the change in the name on those as well as the addition of the new ones.
Here is the previous PR for the accepted values if that helps at all. the Production manifest update will have to wait until all the templates get approved so you will only need to worry about the lower env additions/updates (prod & lower have to be separate PRs either way), but will want to create, or have a ticket created, for the prod ENV additions (there should be one in there already for that so same thing