Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions app/controllers/v0/pipe_test_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# frozen_string_literal: true

module V0
class PipeTestController < ApplicationController
include AuthenticationConcern

before_action :authenticate
before_action :require_loa3, only: [:create]

def create
submission = PipeTestSubmission.new(pipe_test_params)

if submission.valid?
submission.save!

Check failure on line 15 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Layout/TrailingWhitespace: Trailing whitespace detected.
job_id = Lighthouse::SubmitPipeTestJob.perform_async(submission.id)
submission.update!(job_id: job_id, status: 'pending')

Check failure on line 17 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Style/HashSyntax: Omit the hash value.

StatsD.increment('api.pipe_test.submission.success')

Check failure on line 20 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Layout/TrailingWhitespace: Trailing whitespace detected.
render json: PipeTestSerializer.new(submission), status: :created
else
StatsD.increment('api.pipe_test.submission.validation_error')
render json: { errors: submission.errors }, status: :unprocessable_entity
end
rescue => e
StatsD.increment('api.pipe_test.submission.error')
Rails.logger.error "PIPE-TEST submission error: #{e.message}"
render json: { errors: [{ title: 'Internal server error' }] }, status: :internal_server_error
end

def show

Check failure on line 32 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Rails/ActionOrder: Action `show` should appear before `create`.
submission = PipeTestSubmission.find_by!(guid: params[:id])
render json: PipeTestSerializer.new(submission)
rescue ActiveRecord::RecordNotFound
render json: { errors: [{ title: 'Submission not found' }] }, status: :not_found
end

private

def pipe_test_params

Check failure on line 41 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Metrics/MethodLength: Method has too many lines. [21/20]
params.require(:pipe_test).permit(
:form,
:veteran_ssn,
:veteran_first_name,
:veteran_last_name,
:veteran_date_of_birth,
:veteran_phone,
:veteran_email,
:mailing_address_line_1,

Check failure on line 50 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Naming/VariableNumber: Use normalcase for symbol numbers.
:mailing_address_line_2,

Check failure on line 51 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Naming/VariableNumber: Use normalcase for symbol numbers.
:mailing_address_city,
:mailing_address_state,
:mailing_address_postal_code,
:application_type,
:application_details,
:signature_date,
:privacy_agreement_accepted
).merge(
user_uuid: current_user.uuid,
user_account: current_user.user_account
)
end

def require_loa3
raise Common::Exceptions::Forbidden unless current_user.loa3?
end
end
end

Check failure on line 69 in app/controllers/v0/pipe_test_controller.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Layout/TrailingEmptyLines: Final newline missing.
89 changes: 89 additions & 0 deletions app/models/pipe_test_submission.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# frozen_string_literal: true

class PipeTestSubmission < ApplicationRecord
include SetGuid

FORM_ID = 'PIPE-TEST'
STATUSES = %w[pending submitted processed error].freeze

belongs_to :user_account, dependent: nil, optional: false

validates :form, presence: true, inclusion: { in: [FORM_ID] }
validates :status, inclusion: { in: STATUSES }
validates :veteran_ssn, presence: true, format: { with: /\A\d{9}\z/ }
validates :veteran_first_name, :veteran_last_name, presence: true, length: { maximum: 50 }
validates :veteran_date_of_birth, presence: true
validates :veteran_phone, presence: true, format: { with: /\A\d{10}\z/ }
validates :veteran_email, presence: true, format: { with: URI::MailTo::EMAIL_REGEXP }
validates :mailing_address_line_1, :mailing_address_city, :mailing_address_state, presence: true

Check failure on line 18 in app/models/pipe_test_submission.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Naming/VariableNumber: Use normalcase for symbol numbers.
validates :mailing_address_postal_code, presence: true, format: { with: /\A\d{5}(-\d{4})?\z/ }
validates :application_type, presence: true, inclusion: { in: %w[initial renewal amendment] }
validates :signature_date, presence: true
validates :privacy_agreement_accepted, acceptance: true

validate :veteran_date_of_birth_is_valid_date
validate :signature_date_not_in_future

scope :by_status, ->(status) { where(status: status) }

Check failure on line 27 in app/models/pipe_test_submission.rb

View workflow job for this annotation

GitHub Actions / Linting and Security

Style/HashSyntax: Omit the hash value.
scope :submitted_today, -> { where('DATE(created_at) = ?', Date.current) }
scope :pending, -> { where(status: 'pending') }
scope :completed, -> { where(status: %w[submitted processed]) }

encrypts :veteran_ssn
encrypts :veteran_date_of_birth
encrypts :veteran_phone
encrypts :veteran_email

def full_name
"#{veteran_first_name} #{veteran_last_name}".strip
end

def formatted_ssn
return nil unless veteran_ssn
"***-**-#{veteran_ssn.last(4)}"
end

def mailing_address
address_parts = [
mailing_address_line_1,
mailing_address_line_2,
"#{mailing_address_city}, #{mailing_address_state} #{mailing_address_postal_code}"
].compact

address_parts.join("\n")
end

def submitted?
status.in?(%w[submitted processed])
end

def pending?
status == 'pending'
end

private

def veteran_date_of_birth_is_valid_date
return unless veteran_date_of_birth

parsed_date = Date.parse(veteran_date_of_birth.to_s)

if parsed_date > Date.current
errors.add(:veteran_date_of_birth, 'cannot be in the future')
elsif parsed_date < Date.new(1900, 1, 1)
errors.add(:veteran_date_of_birth, 'must be after January 1, 1900')
end
rescue ArgumentError
errors.add(:veteran_date_of_birth, 'is not a valid date')
end

def signature_date_not_in_future
return unless signature_date

if Date.parse(signature_date.to_s) > Date.current
errors.add(:signature_date, 'cannot be in the future')
end
rescue ArgumentError
errors.add(:signature_date, 'is not a valid date')
end
end
45 changes: 45 additions & 0 deletions app/serializers/pipe_test_serializer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
# frozen_string_literal: true

class PipeTestSerializer
include JSONAPI::Serializer

set_id :guid
set_type :pipe_test_submission

attributes :status,
:form,
:submitted_at,
:confirmation_number,
:created_at,
:updated_at

attribute :veteran_info do |object|
{
full_name: object.full_name,
ssn: object.formatted_ssn,
date_of_birth: object.veteran_date_of_birth,
phone: object.veteran_phone,
email: object.veteran_email
}
end

attribute :mailing_address do |object|
{
line_1: object.mailing_address_line_1,
line_2: object.mailing_address_line_2,
city: object.mailing_address_city,
state: object.mailing_address_state,
postal_code: object.mailing_address_postal_code,
formatted_address: object.mailing_address
}
end

attribute :application_info do |object|
{
application_type: object.application_type,
application_details: object.application_details,
signature_date: object.signature_date,
privacy_agreement_accepted: object.privacy_agreement_accepted
}
end
end
86 changes: 86 additions & 0 deletions app/sidekiq/lighthouse/submit_pipe_test_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
# frozen_string_literal: true

module Lighthouse
class SubmitPipeTestJob
include Sidekiq::Worker
include SentryLogging

sidekiq_options retry: 3, queue: 'low'

def perform(submission_id)
submission = PipeTestSubmission.find(submission_id)

StatsD.increment('worker.lighthouse.submit_pipe_test.started')

# Generate PDF from submission data
pdf_content = generate_pdf(submission)

# Submit to Lighthouse Benefits Intake API
response = submit_to_lighthouse(submission, pdf_content)

if response['data']
confirmation_number = response.dig('data', 'attributes', 'confirmationNumber')
submission.update!(
status: 'submitted',
submitted_at: Time.current,
confirmation_number: confirmation_number,
lighthouse_submission_id: response.dig('data', 'id')
)

StatsD.increment('worker.lighthouse.submit_pipe_test.success')
Rails.logger.info "PIPE-TEST submission #{submission.guid} submitted successfully"
else
handle_submission_error(submission, 'Invalid response from Lighthouse API')
end

rescue => e
handle_submission_error(submission, e.message)
raise
end

private

def generate_pdf(submission)
# Generate PDF content using submission data
# This would integrate with the PDF generation service
pdf_generator = Forms::PipeTestPdfGenerator.new(submission)
pdf_generator.generate
end

def submit_to_lighthouse(submission, pdf_content)
lighthouse_service = BenefitsIntake::Service.new

metadata = {
'veteranFirstName' => submission.veteran_first_name,
'veteranLastName' => submission.veteran_last_name,
'fileNumber' => submission.veteran_ssn.last(4),
'zipCode' => submission.mailing_address_postal_code,
'source' => 'VA.gov',
'docType' => submission.form,
'businessLine' => 'NCA' # Assuming National Cemetery Administration
}

lighthouse_service.upload_form(
pdf_content,
metadata,
submission.guid
)
end

def handle_submission_error(submission, error_message)
submission&.update!(
status: 'error',
error_message: error_message
)

StatsD.increment('worker.lighthouse.submit_pipe_test.error')
log_exception_to_sentry(
StandardError.new("PIPE-TEST submission failed: #{error_message}"),
{
submission_id: submission&.id,
submission_guid: submission&.guid
}
)
end
end
end
11 changes: 11 additions & 0 deletions config/routes/pipe_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

Rails.application.routes.draw do
namespace :v0, defaults: { format: 'json' } do
resources :pipe_test, only: [:create, :show] do
collection do
get :status
end
end
end
end
Loading
Loading