From beda804251c8e145f553dad55f55dd8717c7e41e Mon Sep 17 00:00:00 2001 From: Wayne Weibel Date: Tue, 15 Oct 2024 17:48:59 -0400 Subject: [PATCH] PBP 94672 Pension and Burial ZSF manual remediation script (#18829) --- .github/CODEOWNERS | 2 + Gemfile | 2 + Gemfile.lock | 4 + modules/burials/.adr-dir | 1 + modules/burials/.gitignore | 22 +++ modules/burials/.irbrc | 5 + modules/burials/.rspec | 7 + modules/burials/Gemfile | 16 ++ modules/burials/README.md | 5 + modules/burials/Rakefile | 18 +++ .../app/controllers/burials/v0/.gitkeep | 0 modules/burials/app/models/burials/.gitkeep | 0 modules/burials/app/sidekiq/burials/.gitkeep | 0 .../app/swagger/swagger/requests/.gitkeep | 0 modules/burials/bin/rails | 16 ++ modules/burials/burials.gemspec | 19 +++ modules/burials/config/routes.rb | 7 + .../adr/0001-record-architecture-decisions.md | 41 +++++ ...002-use-modules-folder-for-burials-code.md | 22 +++ modules/burials/documentation/readme.md | 58 +++++++ modules/burials/lib/burials.rb | 17 +++ modules/burials/lib/burials/engine.rb | 30 ++++ modules/burials/lib/burials/version.rb | 13 ++ .../manual_remediation.rb | 142 ++++++++++++++++++ modules/burials/spec/spec_helper.rb | 21 +++ modules/pensions/README.md | 2 + modules/pensions/documentation/readme.md | 23 ++- modules/pensions/lib/pensions.rb | 5 + modules/pensions/lib/pensions/engine.rb | 6 + .../manual_remediation.rb | 120 +++++++++++++++ 30 files changed, 610 insertions(+), 14 deletions(-) create mode 100644 modules/burials/.adr-dir create mode 100644 modules/burials/.gitignore create mode 100644 modules/burials/.irbrc create mode 100644 modules/burials/.rspec create mode 100644 modules/burials/Gemfile create mode 100644 modules/burials/README.md create mode 100644 modules/burials/Rakefile create mode 100644 modules/burials/app/controllers/burials/v0/.gitkeep create mode 100644 modules/burials/app/models/burials/.gitkeep create mode 100644 modules/burials/app/sidekiq/burials/.gitkeep create mode 100644 modules/burials/app/swagger/swagger/requests/.gitkeep create mode 100755 modules/burials/bin/rails create mode 100644 modules/burials/burials.gemspec create mode 100644 modules/burials/config/routes.rb create mode 100644 modules/burials/documentation/adr/0001-record-architecture-decisions.md create mode 100644 modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md create mode 100644 modules/burials/documentation/readme.md create mode 100644 modules/burials/lib/burials.rb create mode 100644 modules/burials/lib/burials/engine.rb create mode 100644 modules/burials/lib/burials/version.rb create mode 100644 modules/burials/lib/zero_silent_failures/manual_remediation.rb create mode 100644 modules/burials/spec/spec_helper.rb create mode 100644 modules/pensions/lib/zero_silent_failures/manual_remediation.rb diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index c109b149c9..aa0e554c0b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -796,6 +796,7 @@ docs/deployment @department-of-veterans-affairs/va-api-engineers @department-of- docs/deployment/information.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/HISTORY.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/index.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +docs/modules @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/setup/betamocks.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/setup/binstubs.md @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group docs/setup/docker.md @department-of-veterans-affairs/backend-review-group @department-of-veterans-affairs/va-api-engineers @@ -1005,6 +1006,7 @@ modules/appeals_api @department-of-veterans-affairs/lighthouse-banana-peels @dep modules/apps_api @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/lighthouse-pivot modules/ask_va_api @department-of-veterans-affairs/ask-va-team @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group modules/avs @department-of-veterans-affairs/after-visit-summary @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/backend-review-group +modules/burials @department-of-veterans-affairs/pension-and-burials @department-of-veterans-affairs/backend-review-group modules/check_in @department-of-veterans-affairs/va-api-engineers @department-of-veterans-affairs/vsa-healthcare-health-quest-1-backend @department-of-veterans-affairs/patient-check-in @department-of-veterans-affairs/backend-review-group modules/claims_api @department-of-veterans-affairs/lighthouse-dash modules/covid_research @department-of-veterans-affairs/long-covid diff --git a/Gemfile b/Gemfile index 1abfc8eca2..6092e450b5 100644 --- a/Gemfile +++ b/Gemfile @@ -11,6 +11,7 @@ path 'modules' do gem 'apps_api' gem 'ask_va_api' gem 'avs' + gem 'burials' gem 'check_in' gem 'claims_api' gem 'covid_research' @@ -137,6 +138,7 @@ gem 'rails-session_cookie' gem 'redis' gem 'redis-namespace' gem 'request_store' +gem 'require_all' gem 'restforce' gem 'rgeo-geojson' gem 'roo' diff --git a/Gemfile.lock b/Gemfile.lock index 4a7dcf1fc8..64f5d99469 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -93,6 +93,7 @@ PATH sidekiq ask_va_api (0.1.0) avs (0.1.0) + burials (0.1.0) check_in (0.1.0) claims_api (0.0.1) dry-schema @@ -855,6 +856,7 @@ GEM uber (< 0.2.0) request_store (1.7.0) rack (>= 1.4) + require_all (3.0.0) restforce (7.5.0) faraday (>= 1.1.0, < 2.12.0) faraday-follow_redirects (<= 0.3.0, < 1.0.0) @@ -1128,6 +1130,7 @@ DEPENDENCIES brakeman breakers bundler-audit + burials! byebug carrierwave carrierwave-aws @@ -1246,6 +1249,7 @@ DEPENDENCIES redis-namespace representation_management! request_store + require_all restforce rgeo-geojson roo diff --git a/modules/burials/.adr-dir b/modules/burials/.adr-dir new file mode 100644 index 0000000000..469b5222fd --- /dev/null +++ b/modules/burials/.adr-dir @@ -0,0 +1 @@ +documentation/adr diff --git a/modules/burials/.gitignore b/modules/burials/.gitignore new file mode 100644 index 0000000000..9561900a83 --- /dev/null +++ b/modules/burials/.gitignore @@ -0,0 +1,22 @@ +# See https://help.github.com/articles/ignoring-files for more about ignoring files. +# +# If you find yourself ignoring temporary files generated by your text editor +# or operating system, you probably want to add a global ignore instead: +# git config --global core.excludesfile '~/.gitignore_global' + +# Ignore bundler config. +.bundle +.envrc + +# Ignore all logfiles and tempfiles. +/log/* +!/log/.keep +/tmp/* +!/tmp/.keep + +# Ignore generated directories +/coverage +/reports + +# ignore yardoc generation +.yardoc/ diff --git a/modules/burials/.irbrc b/modules/burials/.irbrc new file mode 100644 index 0000000000..c8d7196216 --- /dev/null +++ b/modules/burials/.irbrc @@ -0,0 +1,5 @@ +# Disable autocomplete in deployed environments +# to help prevent running unintended commands +if ENV['RAILS_ENV'] == 'production' + IRB.conf[:USE_AUTOCOMPLETE] = false +end diff --git a/modules/burials/.rspec b/modules/burials/.rspec new file mode 100644 index 0000000000..683eea9e1a --- /dev/null +++ b/modules/burials/.rspec @@ -0,0 +1,7 @@ +--color +--require spec_helper +--format progress +<% if ENV['CI'] %> +--format RspecJunitFormatter +--out log/rspec.xml +<% end %> diff --git a/modules/burials/Gemfile b/modules/burials/Gemfile new file mode 100644 index 0000000000..a2af83a5bb --- /dev/null +++ b/modules/burials/Gemfile @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +# Declare your gem's dependencies in simple_forms_api.gemspec. +# Bundler will treat runtime dependencies like base dependencies, and +# development dependencies will be added by default to the :development group. +gemspec + +# Declare any dependencies that are still in development here instead of in +# your gemspec. These might include edge Rails or gems from your path or +# Git. Remember to move these dependencies to your gemspec before releasing +# your gem to rubygems.org. + +# To use a debugger +# gem 'byebug', group: [:development, :test] diff --git a/modules/burials/README.md b/modules/burials/README.md new file mode 100644 index 0000000000..00eaf5a6af --- /dev/null +++ b/modules/burials/README.md @@ -0,0 +1,5 @@ +# Burials + +Pension & Burial Program (PBP) + +Engineering related documentation can be found under [/documentation/](./documentation/) diff --git a/modules/burials/Rakefile b/modules/burials/Rakefile new file mode 100644 index 0000000000..0433dd142e --- /dev/null +++ b/modules/burials/Rakefile @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end + +require 'bundler/gem_tasks' + +unless Rails.env.production? + require 'rspec/core/rake_task' + task(spec: :environment).clear + RSpec::Core::RakeTask.new(:spec) do |t| + t.pattern = Dir.glob(['spec/**/*_spec.rb']) + t.verbose = false + end +end diff --git a/modules/burials/app/controllers/burials/v0/.gitkeep b/modules/burials/app/controllers/burials/v0/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/burials/app/models/burials/.gitkeep b/modules/burials/app/models/burials/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/burials/app/sidekiq/burials/.gitkeep b/modules/burials/app/sidekiq/burials/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/burials/app/swagger/swagger/requests/.gitkeep b/modules/burials/app/swagger/swagger/requests/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/burials/bin/rails b/modules/burials/bin/rails new file mode 100755 index 0000000000..8f9430795e --- /dev/null +++ b/modules/burials/bin/rails @@ -0,0 +1,16 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# This command will automatically be run when you run "rails" with Rails gems +# installed from the root of your application. + +ENGINE_ROOT = File.expand_path('..', __dir__) +ENGINE_PATH = File.expand_path('../lib/burials/engine', __dir__) +APP_PATH = File.expand_path('../test/dummy/config/application', __dir__) + +# Set up gems listed in the Gemfile. +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__) +require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE']) + +require 'rails/all' +require 'rails/engine/commands' diff --git a/modules/burials/burials.gemspec b/modules/burials/burials.gemspec new file mode 100644 index 0000000000..2ac4d9202e --- /dev/null +++ b/modules/burials/burials.gemspec @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +$LOAD_PATH.push File.expand_path('lib', __dir__) + +require 'burials/version' + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |spec| + spec.name = 'burials' + spec.version = Burials::VERSION + spec.authors = ['Benefits Burials'] + spec.email = [''] + spec.homepage = 'https://api.va.gov' + spec.summary = 'An api.va.gov module' + spec.description = 'This module was auto-generated please update this description' + spec.license = 'CC0-1.0' + + spec.files = Dir['{app,config,db,lib}/**/*', 'Rakefile', 'README.md'] +end diff --git a/modules/burials/config/routes.rb b/modules/burials/config/routes.rb new file mode 100644 index 0000000000..39d2a9c9d2 --- /dev/null +++ b/modules/burials/config/routes.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +Burials::Engine.routes.draw do + namespace :v0, defaults: { format: :json } do + resources :claims, only: %i[create show] + end +end diff --git a/modules/burials/documentation/adr/0001-record-architecture-decisions.md b/modules/burials/documentation/adr/0001-record-architecture-decisions.md new file mode 100644 index 0000000000..907b08bf92 --- /dev/null +++ b/modules/burials/documentation/adr/0001-record-architecture-decisions.md @@ -0,0 +1,41 @@ +# 1. Record architecture decisions + +Date: 2024-06-14 + +## Status + +Accepted + +## Context + +We need to record the architectural decisions made on this project. + +## Decision Documentation + +We will use Architecture Decision Records, as [described by Michael Nygard](http://thinkrelevance.com/blog/2011/11/15/documenting-architecture-decisions). + +### Using adr-tools + +This repository makes use of [adr-tools](https://github.com/npryce/adr-tools/tree/master) to record architectural decisions as part of the code base. + +There are two uses for this, recording a new decision and superseding an existing decision. + +#### Recording a new decision + +To create a new decision use the adr new command: + +```bash + adr new +``` + +#### Superseding an existing decision + +To overwrite an existing decision you can add the -s flag followed by which is getting overwritten. In this example we are overwriting decision 9 with an updated decision: + +```bash +adr new -s 9 +``` + +## Consequences + +See Michael Nygard's article, linked above. For a lightweight ADR toolset, see Nat Pryce's [adr-tools](https://github.com/npryce/adr-tools). diff --git a/modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md b/modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md new file mode 100644 index 0000000000..fb8329b129 --- /dev/null +++ b/modules/burials/documentation/adr/0002-use-modules-folder-for-burials-code.md @@ -0,0 +1,22 @@ +# 2. Move burials application to modules folder + +Date: 2024-10-10 + +## Status + +Accepted + +## Context + +The vets-api is a large monorepo with many overlapping forms. The tangle of code between applications has made it difficult for teams to iterate without impacting others. + +## Decision + +In an effort to isolate code, the PBP team has decided to take advantage of [Ruby on Rails Engines](https://guides.rubyonrails.org/engines.html) to create a separate application for the 21P-530EZ form (burials). Engines can be isolated from their host applications which will allow for us to: + +- Isolate the code pertinent to Burials +- Work toward running a CI/CD that can be applied only to Burial code + +## Consequences + +The result of this change will allow for the PBP team to more quickly iterate and innovate on future changes. There is a risk that isolating burial code will result in a lot of duplication of code. The longer term goal would be to move common benefits logic into a module of its own as is being done for burial code. diff --git a/modules/burials/documentation/readme.md b/modules/burials/documentation/readme.md new file mode 100644 index 0000000000..2affdf7581 --- /dev/null +++ b/modules/burials/documentation/readme.md @@ -0,0 +1,58 @@ +# Burials Documentation + +Pension & Burial Program (PBP) + +## ADR + +The PBP team uses [ADR Tools](https://github.com/npryce/adr-tools/tree/master) to document important engineering related decisions for the vets-api repo. The goal is to capture the technical decisions our group makes so that anyone new to our team or following behind will be able to understand the reasons for the decisions. + +Additional architectural decisions made by other teams can be found here: +https://github.com/department-of-veterans-affairs/va.gov-team-sensitive/tree/master/teams/benefits/architectural-decision-records + +| Decision | +| ----------------------------------------------------------------------------------------------------------- | +| [Use ADR to document important engineering decisions](./adr/0001-record-architecture-decisions.md) | +| [Move the burials specific code to the modules folder](./adr/0002-use-modules-folder-for-burials-code.md) | +| | + +## Folder structure + +For more information on the Ruby on Rails directory structure, please refer to https://github.com/jwipeout/rails-directory-structure-guide + +The current folder structure generally follows the default directory structure that **Ruby on Rails** comes with. + +##### App Folder + +- At a high level, within the app folder, there are [controllers](https://guides.rubyonrails.org/action_controller_overview.html) and [models](https://guides.rubyonrails.org/active_record_basics.html). Ruby on Rails uses a MVC (model, view, controller) architecture pattern. There is little historical context or documentation on the choice of V0 or V1 for the controllers. +- There are also a [sidekiq](https://github.com/sidekiq/sidekiq) and [swagger](https://swagger.io/) folders. + +##### DB Folder + +- The db folder contains the schema and migrations used for the application. + +##### Lib Folder + +- The lib folder is intended for common code or code that can be reused by other teams. It is also where the code for interfacing with external APIs lives. + +##### Config Folder + +- The config folder is where most of the configuration files for the main rails app, plugins, etc. are housed + +##### Spec Folder + +- Contains the tests for vets-api + +## Team + +| Name | Email Address | +| ------------ | ------------------------- | +| Matt Knight | matt.knight@coforma.io | +| Wayne Weibel | wayne.weibel@adhocteam.us | +| Tai Wilkin | tai.wilkin@coforma.io | +| Todd Rizzolo | todd.rizzolo@adhocteam.us | +| Daniel Lim | daniel.lim@adhocteam.us | +| Bryan Alexander | bryan.alexander@adhocteam.us | + +## Troubleshooting + +## diff --git a/modules/burials/lib/burials.rb b/modules/burials/lib/burials.rb new file mode 100644 index 0000000000..6be4909b11 --- /dev/null +++ b/modules/burials/lib/burials.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require 'burials/engine' + +## +# Burial 21P-530EZ Module +# +module Burials + # API Version 0 + module V0 + end + + # ZeroSilentFailures + # @see lib/zero_silent_failures + module ZeroSilentFailures + end +end diff --git a/modules/burials/lib/burials/engine.rb b/modules/burials/lib/burials/engine.rb new file mode 100644 index 0000000000..65ca73b39f --- /dev/null +++ b/modules/burials/lib/burials/engine.rb @@ -0,0 +1,30 @@ +# frozen_string_literal: true + +module Burials + # @see https://api.rubyonrails.org/classes/Rails/Engine.html + class Engine < ::Rails::Engine + isolate_namespace Burials + config.generators.api_only = true + + initializer 'burials.factories', after: 'factory_bot.set_factory_paths' do + FactoryBot.definition_file_paths << File.expand_path('../../spec/factories', __dir__) if defined?(FactoryBot) + end + + initializer 'burials.zero_silent_failures' do |app| + app.config.to_prepare do + require_all "#{__dir__}/../zero_silent_failures" + end + end + + # TODO: move PDFFill library to this module + # initializer 'burials.register_form' do |app| + # app.config.to_prepare do + # require 'pdf_fill/filler' + # require_relative '../pdf_fill/va21p530v2' + + # # Register our Burial Pdf Fill form + # ::PdfFill::Filler.register_form(Burials::PdfFill::Va21p530v2::FORM_ID, Burials::PdfFill::Va21p530v2) + # end + # end + end +end diff --git a/modules/burials/lib/burials/version.rb b/modules/burials/lib/burials/version.rb new file mode 100644 index 0000000000..9da0a5a9a1 --- /dev/null +++ b/modules/burials/lib/burials/version.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +module Burials + ## + # The module path + # + MODULE_PATH = 'modules/burials' + + ## + # The module version + # + VERSION = '0.1.0' +end diff --git a/modules/burials/lib/zero_silent_failures/manual_remediation.rb b/modules/burials/lib/zero_silent_failures/manual_remediation.rb new file mode 100644 index 0000000000..48bd352248 --- /dev/null +++ b/modules/burials/lib/zero_silent_failures/manual_remediation.rb @@ -0,0 +1,142 @@ +# frozen_string_literal: true + +require 'common/file_helpers' +require 'pdf_utilities/datestamp_pdf' + +module Burials + module ZeroSilentFailures + class ManualRemediation + def package_claim(saved_claim_id) + @claim = SavedClaim::Burial.find(saved_claim_id) + + generate_metadata + + generate_form_pdf + + generate_attachment_pdfs + + zipfile = zip_files(files) + Rails.logger.info("Packaged #{claim.form_id} #{claim.id} - #{zipfile}") + + if Settings.vsp_environment == 'production' + link = aws_upload_zipfile(zipfile) + Rails.logger.info("Download #{link}") + Common::FileHelpers.delete_file_if_exists(zipfile) + end + end + + private + + attr_reader :claim + + def files + @files ||= [] + end + + def generate_metadata + form = claim.parsed_form + address = form['claimantAddress'] || form['veteranAddress'] + + lighthouse_benefit_intake_submission = FormSubmission.where(saved_claim_id: claim.id).order(id: :asc).last + + metadata = { + claimId: claim.id, + docType: claim.form_id, + formStartDate: claim.form_start_date, + claimSubmissionDate: claim.created_at, + claimConfirmation: claim.guid, + veteranFirstName: form['veteranFullName']['first'], + veteranLastName: form['veteranFullName']['last'], + fileNumber: form['vaFileNumber'] || form['veteranSocialSecurityNumber'], + zipCode: address['postalCode'], + businessLine: claim.business_line, + lighthouseBenefitIntakeSubmissionUUID: lighthouse_benefit_intake_submission&.benefits_intake_uuid, + lighthouseBenefitIntakeSubmissionDate: lighthouse_benefit_intake_submission&.created_at + } + + metafile = Common::FileHelpers.generate_random_file(metadata.to_json) + files << { name: "#{claim.form_id}_#{claim.id}-metadata.json", path: metafile } + end + + def generate_form_pdf + filepath = claim.to_pdf + Rails.logger.info "Stamping #{claim.form_id} #{claim.id} - #{filepath}" + stamped = stamp_pdf(filepath, claim.created_at) + if ['21P-530V2'].include?(claim.form_id) + stamped = stamped_pdf_with_form(claim.form_id, stamped, + claim.created_at) + end + files << { name: File.basename(filepath), path: stamped } + end + + def generate_attachment_pdfs + claim.persistent_attachments.each do |pa| + filename = "#{claim.form_id}_#{claim.id}-attachment_#{pa.id}.pdf" + filepath = pa.to_pdf + Rails.logger.info "Stamping #{claim.form_id} #{claim.id} Attachment #{pa.id} - #{filepath}" + stamped = stamp_pdf(filepath, claim.created_at) + if ['21P-530V2'].include?(claim.form_id) + stamped = stamped_pdf_with_form(claim.form_id, stamped, + claim.created_at) + end + files << { name: filename, path: stamped } + end + end + + def stamp_pdf(pdf_path, timestamp = nil) + begin + datestamp = PDFUtilities::DatestampPdf.new(pdf_path).run(text: 'VA.GOV', x: 5, y: 5, timestamp:) + watermark = PDFUtilities::DatestampPdf.new(datestamp).run( + text: 'FDC Reviewed - VA.gov Submission', + x: 400, + y: 770, + text_only: true, + timestamp: + ) + rescue + Rails.logger.error "Error stamping pdf: #{pdf_path}" + end + + watermark || pdf_path + end + + def stamped_pdf_with_form(form_id, path, timestamp) + PDFUtilities::DatestampPdf.new(path).run( + text: 'Application Submitted on va.gov', + x: 425, + y: 675, + text_only: true, # passing as text only because we override how the date is stamped in this instance + timestamp:, + page_number: 5, + size: 9, + template: "lib/pdf_fill/forms/pdfs/#{form_id}.pdf", + multistamp: true + ) + end + + def zip_files(files) + zip_file_path = "#{Common::FileHelpers.random_file_path}.zip" + Zip::File.open(zip_file_path, Zip::File::CREATE) do |zipfile| + files.each do |file| + Rails.logger.info(file) + begin + zipfile.add(file[:name], file[:path]) + rescue + Rails.logger.error "Error adding to zip: #{file}" + end + end + end + zip_file_path + end + + def aws_upload_zipfile(zipfile) + s3_resource = Aws::S3::Resource.new(region: Settings.vba_documents.s3.region, + access_key_id: Settings.vba_documents.s3.aws_access_key_id, + secret_access_key: Settings.vba_documents.s3.aws_secret_access_key) + obj = s3_resource.bucket(Settings.vba_documents.s3.bucket).object(File.basename(zipfile)) + obj.upload_file(zipfile, content_type: Mime[:zip].to_s) + obj.presigned_url(:get, expires_in: 1.day.to_i) + end + end + end +end diff --git a/modules/burials/spec/spec_helper.rb b/modules/burials/spec/spec_helper.rb new file mode 100644 index 0000000000..61f0ddb788 --- /dev/null +++ b/modules/burials/spec/spec_helper.rb @@ -0,0 +1,21 @@ +# frozen_string_literal: true + +require 'rspec/rails' + +RSpec.configure { |config| config.use_transactional_fixtures = true } + +# By default run SimpleCov, but allow an environment variable to disable. +unless ENV['NOCOVERAGE'] + require 'simplecov' + + SimpleCov.start 'rails' do + track_files '**/{app,lib}/**/*.rb' + + add_filter 'app/swagger' + + if ENV['CI'] + SimpleCov.minimum_coverage 90 + SimpleCov.refuse_coverage_drop + end + end +end diff --git a/modules/pensions/README.md b/modules/pensions/README.md index 6fee25156f..6b911b3a5c 100644 --- a/modules/pensions/README.md +++ b/modules/pensions/README.md @@ -1,3 +1,5 @@ # Pensions +Pension & Burial Program (PBP) + Engineering related documentation can be found under [/documentation/](./documentation/) diff --git a/modules/pensions/documentation/readme.md b/modules/pensions/documentation/readme.md index e0cb7f40ac..9913080e66 100644 --- a/modules/pensions/documentation/readme.md +++ b/modules/pensions/documentation/readme.md @@ -1,5 +1,7 @@ # Pensions Documentation +Pension & Burial Program (PBP) + ## ADR The pensions team uses [ADR Tools](https://github.com/npryce/adr-tools/tree/master) to document important engineering related decisions for the vets-api repo. The goal is to capture the technical decisions our group makes so that anyone new to our team or following behind will be able to understand the reasons for the decisions. @@ -38,11 +40,6 @@ The current folder structure generally follows the default directory structure t - The config folder is where most of the configuration files for the main rails app, plugins, etc. are housed -##### Modules Folder - -- The modules folder has been a source of confusion for teams within vets-api. Oddly, the code for the [Lighthouse API's](https://developer.va.gov/explore) exists within the modules folder, making it a part of the overall monorepo of vets-api. It has been discussed that at some point the Lighthouse code will be moved out of vets-api. -- The original advice we received was that no one should touch the modules folder because the code was owned by the Lighthouse team. That no longer seems to be the case. - ##### Spec Folder - Contains the tests for vets-api @@ -61,16 +58,14 @@ The new folder structure will look like: ## Team -August 2023 - August 2024 Team - -| Name | Email Address | -| ------------ | ------------------------- | -| Matt Knight | matt.knight@coforma.io | -| Wayne Weibel | wayne.weibel@adhocteam.us | -| Tai Wilkin | tai.wilkin@coforma.io | -| Todd Rizzolo | todd.rizzolo@adhocteam.us | +| Name | Email Address | +| ------------ | ------------------------- | +| Matt Knight | matt.knight@coforma.io | +| Wayne Weibel | wayne.weibel@adhocteam.us | +| Tai Wilkin | tai.wilkin@coforma.io | +| Todd Rizzolo | todd.rizzolo@adhocteam.us | +| Daniel Lim | daniel.lim@adhocteam.us | | Bryan Alexander | bryan.alexander@adhocteam.us | -| Daniel Lim | daniel.lim@adhocteam.us | ## Troubleshooting diff --git a/modules/pensions/lib/pensions.rb b/modules/pensions/lib/pensions.rb index 600b3266db..b2c699e983 100644 --- a/modules/pensions/lib/pensions.rb +++ b/modules/pensions/lib/pensions.rb @@ -19,4 +19,9 @@ module PdfFill # @see https://docs.sentry.io/platforms/ruby/enriching-events/tags/ module TagSentry end + + # ZeroSilentFailures + # @see lib/zero_silent_failures + module ZeroSilentFailures + end end diff --git a/modules/pensions/lib/pensions/engine.rb b/modules/pensions/lib/pensions/engine.rb index 744219546d..fdd5678978 100644 --- a/modules/pensions/lib/pensions/engine.rb +++ b/modules/pensions/lib/pensions/engine.rb @@ -10,6 +10,12 @@ class Engine < ::Rails::Engine FactoryBot.definition_file_paths << File.expand_path('../../spec/factories', __dir__) if defined?(FactoryBot) end + initializer 'pensions.zero_silent_failures' do |app| + app.config.to_prepare do + require_all "#{__dir__}/../zero_silent_failures" + end + end + initializer 'pensions.register_form' do |app| app.config.to_prepare do require 'pdf_fill/filler' diff --git a/modules/pensions/lib/zero_silent_failures/manual_remediation.rb b/modules/pensions/lib/zero_silent_failures/manual_remediation.rb new file mode 100644 index 0000000000..d86c121fa7 --- /dev/null +++ b/modules/pensions/lib/zero_silent_failures/manual_remediation.rb @@ -0,0 +1,120 @@ +# frozen_string_literal: true + +require 'common/file_helpers' +require 'pdf_utilities/datestamp_pdf' + +module Pensions + module ZeroSilentFailures + class ManualRemediation + def package_claim(saved_claim_id) + @claim = Pensions::SavedClaim.find(saved_claim_id) + + generate_metadata + + generate_form_pdf + + generate_attachment_pdfs + + zipfile = zip_files(files) + Rails.logger.info("Packaged #{claim.form_id} #{claim.id} - #{zipfile}") + + if Settings.vsp_environment == 'production' + link = aws_upload_zipfile(zipfile) + Rails.logger.info("Download #{link}") + Common::FileHelpers.delete_file_if_exists(zipfile) + end + end + + private + + attr_reader :claim + + def files + @files ||= [] + end + + def generate_metadata + form = claim.parsed_form + address = form['claimantAddress'] || form['veteranAddress'] + + lighthouse_benefit_intake_submission = FormSubmission.where(saved_claim_id: claim.id).order(id: :asc).last + + metadata = { + claimId: claim.id, + docType: claim.form_id, + formStartDate: claim.form_start_date, + claimSubmissionDate: claim.created_at, + claimConfirmation: claim.guid, + veteranFirstName: form['veteranFullName']['first'], + veteranLastName: form['veteranFullName']['last'], + fileNumber: form['vaFileNumber'] || form['veteranSocialSecurityNumber'], + zipCode: address['postalCode'], + businessLine: claim.business_line, + lighthouseBenefitIntakeSubmissionUUID: lighthouse_benefit_intake_submission&.benefits_intake_uuid, + lighthouseBenefitIntakeSubmissionDate: lighthouse_benefit_intake_submission&.created_at + } + + metafile = Common::FileHelpers.generate_random_file(metadata.to_json) + files << { name: "#{claim.form_id}_#{claim.id}-metadata.json", path: metafile } + end + + def generate_form_pdf + filepath = claim.to_pdf + Rails.logger.info "Stamping #{claim.form_id} #{claim.id} - #{filepath}" + stamped = stamp_pdf(filepath, claim.created_at) + files << { name: File.basename(filepath), path: stamped } + end + + def generate_attachment_pdfs + claim.persistent_attachments.each do |pa| + filename = "#{claim.form_id}_#{claim.id}-attachment_#{pa.id}.pdf" + filepath = pa.to_pdf + Rails.logger.info "Stamping #{claim.form_id} #{claim.id} Attachment #{pa.id} - #{filepath}" + stamped = stamp_pdf(filepath, claim.created_at) + files << { name: filename, path: stamped } + end + end + + def stamp_pdf(pdf_path, timestamp = nil) + begin + datestamp = PDFUtilities::DatestampPdf.new(pdf_path).run(text: 'VA.GOV', x: 5, y: 5, timestamp:) + watermark = PDFUtilities::DatestampPdf.new(datestamp).run( + text: 'FDC Reviewed - VA.gov Submission', + x: 429, + y: 770, + text_only: true, + timestamp: + ) + rescue + Rails.logger.error "Error stamping pdf: #{pdf_path}" + end + + watermark || pdf_path + end + + def zip_files(files) + zip_file_path = "#{Common::FileHelpers.random_file_path}.zip" + Zip::File.open(zip_file_path, Zip::File::CREATE) do |zipfile| + files.each do |file| + Rails.logger.info(file) + begin + zipfile.add(file[:name], file[:path]) + rescue + Rails.logger.error "Error adding to zip: #{file}" + end + end + end + zip_file_path + end + + def aws_upload_zipfile(zipfile) + s3_resource = Aws::S3::Resource.new(region: Settings.vba_documents.s3.region, + access_key_id: Settings.vba_documents.s3.aws_access_key_id, + secret_access_key: Settings.vba_documents.s3.aws_secret_access_key) + obj = s3_resource.bucket(Settings.vba_documents.s3.bucket).object(File.basename(zipfile)) + obj.upload_file(zipfile, content_type: Mime[:zip].to_s) + obj.presigned_url(:get, expires_in: 1.day.to_i) + end + end + end +end