diff --git a/.docker/config/cable.yml b/.docker/config/cable.yml new file mode 100644 index 00000000..20178b86 --- /dev/null +++ b/.docker/config/cable.yml @@ -0,0 +1,14 @@ +development: + adapter: redis + url: redis://localhost:6379/1 + channel_prefix: medicaid_gateway_development + +test: + adapter: async + url: redis://localhost:6379/1 + channel_prefix: medicaid_gateway_test + +production: + adapter: redis + url: redis://<%= ENV['REDIS_HOST_MEDICAID_GATEWAY'] %>:6379/1 + channel_prefix: medicaid_gateway_production diff --git a/.vscode/settings.json b/.vscode/settings.json index 13d7db93..8a5b228c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -7,5 +7,8 @@ }, "[ruby]": { "editor.defaultFormatter": "castwide.solargraph" + }, + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features" } } diff --git a/Gemfile b/Gemfile index 1ab6bfd4..0d674dab 100644 --- a/Gemfile +++ b/Gemfile @@ -8,8 +8,8 @@ ruby '2.7.2' # Mount the Engines gem 'mitc_service', path: 'components/mitc_service' -gem 'aca_entities', git: 'https://github.com/ideacrew/aca_entities.git', branch: 'release_0.10.0' -gem 'event_source', git: 'https://github.com/ideacrew/event_source.git', branch: 'release_0.5.5' +gem 'aca_entities', git: 'https://github.com/ideacrew/aca_entities.git', branch: 'trunk' +gem 'event_source', git: 'https://github.com/ideacrew/event_source.git', branch: 'trunk' # Bundle edge Rails instead: gem 'rails', github: 'rails/rails', branch: 'main' gem 'rails', '~> 6.1.3' @@ -31,6 +31,8 @@ gem 'jbuilder', '~> 2.7' gem 'bootstrap', '~> 5.1.0' # To prettify json payloads gem 'awesome_print' +# For interactive pieces +gem "stimulus_reflex", "~> 3.4" # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', '>= 1.4.4', require: false @@ -78,4 +80,4 @@ gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby] group :production do gem 'eye', '0.10.0' gem 'unicorn', '~> 4.8' -end +end \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 8279a1f4..2ffa3c09 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GIT remote: https://github.com/ideacrew/aca_entities.git - revision: acccd54c96e8d9ef48e239a56ecd2b6536e88ff2 - branch: release_0.10.0 + revision: abd4c4e4bed30c5c1008479545df41d4f9e494b9 + branch: trunk specs: aca_entities (0.9.0) deep_merge @@ -17,8 +17,8 @@ GIT GIT remote: https://github.com/ideacrew/event_source.git - revision: 4ad8aae6c76d0a0fd64907861c9a5f52c17bc47a - branch: release_0.5.5 + revision: 29393ebb04df8f57ccb536da4635087c8c8bde0b + branch: trunk specs: event_source (0.5.5) bunny (>= 2.14) @@ -162,6 +162,9 @@ GEM amq-protocol (~> 2.3, >= 2.3.1) sorted_set (~> 1, >= 1.0.2) byebug (11.1.3) + cable_ready (4.5.0) + rails (>= 5.2) + thread-local (>= 1.1.0) capybara (3.35.3) addressable mini_mime (>= 0.1.3) @@ -472,7 +475,7 @@ GEM sprockets-rails tilt semantic_range (3.0.0) - set (1.0.1) + set (1.0.2) shoulda-matchers (3.1.3) activesupport (>= 4.0.0) sinatra (2.1.0) @@ -492,7 +495,14 @@ GEM activesupport (>= 4.0) sprockets (>= 3.0.0) state_machines (0.5.0) + stimulus_reflex (3.4.1) + cable_ready (>= 4.5) + nokogiri + rack + rails (>= 5.2) + redis thor (1.1.0) + thread-local (1.1.0) tilt (2.0.10) timers (4.3.3) turbolinks (5.2.1) @@ -561,6 +571,7 @@ DEPENDENCIES sass-rails (>= 6) shoulda-matchers (~> 3) spring (~> 1.7.2) + stimulus_reflex (~> 3.4) turbolinks (~> 5) typhoeus tzinfo-data diff --git a/app/assets/stylesheets/application.scss b/app/assets/stylesheets/application.scss index cbd46a7a..d133e83a 100644 --- a/app/assets/stylesheets/application.scss +++ b/app/assets/stylesheets/application.scss @@ -1 +1,26 @@ @import "bootstrap"; + +kbd { + -moz-background-clip: border; + -moz-background-inline-policy: continuous; + -moz-background-origin: padding; + background: #ffffff none repeat scroll 0 0; + border: none; + color: #000000; + padding: 2px 1px; + white-space: nowrap; +} + +.long-payload { + display: -webkit-box; + -webkit-line-clamp: 10; + -webkit-box-orient: vertical; + overflow: hidden; + text-overflow: ellipsis; +} + +.table-overrides { + table-layout: fixed; + width: 100%; + word-wrap: break-word; +} diff --git a/app/channels/application_cable/connection.rb b/app/channels/application_cable/connection.rb index 8d6c2a1b..5bb35e00 100644 --- a/app/channels/application_cable/connection.rb +++ b/app/channels/application_cable/connection.rb @@ -1,6 +1,14 @@ # frozen_string_literal: true module ApplicationCable + + # stimulus reflex connection differentiator class Connection < ActionCable::Connection::Base + identified_by :session_id + + def connect + self.session_id = request.session.id + reject_unauthorized_connection unless session_id + end end end diff --git a/app/controllers/medicaid/applications_controller.rb b/app/controllers/medicaid/applications_controller.rb new file mode 100644 index 00000000..1275dd4e --- /dev/null +++ b/app/controllers/medicaid/applications_controller.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +module Medicaid + # Determinations from MITC + class ApplicationsController < ActionController::Base + def show + @application = Medicaid::Application.find(params[:id]) + render layout: "application" + end + end +end \ No newline at end of file diff --git a/app/controllers/reports_controller.rb b/app/controllers/reports_controller.rb index 0a35e3d2..91f74813 100644 --- a/app/controllers/reports_controller.rb +++ b/app/controllers/reports_controller.rb @@ -3,44 +3,49 @@ # ReportsController provides API access to reports class ReportsController < ApplicationController + def events + @start_on = start_on || session[:start] || Date.today + @end_on = end_on || session[:end] || Date.today + events = applications + transfers + inbound_transfers + checks + @events = events.map(&:to_event).sort_by { |event| event[:created_at] }.reverse + end + def medicaid_applications - range = range_from_params - applications = Medicaid::Application.where(created_at: range).or(updated_at: range) - render json: applications + render json: Medicaid::Application.where(created_at: range_from_params).or(updated_at: range_from_params) end def medicaid_application_check - @range = range_from_params - @applications = Medicaid::Application.where(created_at: @range).or(updated_at: @range) + @start_on = start_on || session[:ma_start] || Date.today + @end_on = end_on || session[:ma_end] || Date.today + @applications = applications end def account_transfers - @range = range_from_params - @transfers = Aces::Transfer.where(created_at: @range).or(updated_at: @range) + @start_on = start_on || session[:atp_start] || Date.today + @end_on = end_on || session[:atp_end] || Date.today + @transfers = transfers end def account_transfers_to_enroll - @range = range_from_params - @transfers = Aces::InboundTransfer.where(created_at: @range).or(updated_at: @range) + @start_on = start_on || session[:atp_start] || Date.today + @end_on = end_on || session[:atp_end] || Date.today + @transfers = inbound_transfers end def mec_checks - @range = range_from_params - @checks = Aces::MecCheck.where(created_at: @range).or(updated_at: @range) + @start_on = start_on || session[:mc_sent_start] || Date.today + @end_on = session[:mc_sent_end] || Date.today + @checks = checks end def transfer_summary - @range = range_from_params - @start_on = params.fetch(:start_on) if params.key?(:start_on) - @end_on = params.fetch(:end_on) if params.key?(:end_on) - at_sent = Aces::Transfer.where(created_at: @range).or(updated_at: @range) - @at_sent_total = at_sent.count - @at_sent_successful = at_sent.where(failure: nil).count + @start_on = start_on || session[:atp_start] || Date.today + @end_on = end_on || session[:atp_end] || Date.today + @at_sent_total = transfers.count + @at_sent_successful = transfers.where(failure: nil).count @at_sent_failure = @at_sent_total - @at_sent_successful - - at_received = Aces::InboundTransfer.where(created_at: @range).or(updated_at: @range) - @at_received_total = at_received.count - @at_received_successful = at_received.where(failure: nil).count + @at_received_total = inbound_transfers.count + @at_received_successful = inbound_transfers.where(failure: nil).count @at_received_failure = @at_received_total - @at_received_successful end @@ -51,4 +56,32 @@ def range_from_params end_on = params.key?(:end_on) ? Date.strptime(params.fetch(:end_on), "%m/%d/%Y") : Time.now.utc start_on.beginning_of_day..end_on.end_of_day end + + def start_on + Date.strptime(params.fetch(:start_on), "%m/%d/%Y") if params.key?(:start_on) + end + + def end_on + Date.strptime(params.fetch(:end_on), "%m/%d/%Y") if params.key?(:end_on) + end + + def range + @start_on.beginning_of_day..@end_on.end_of_day + end + + def applications + Medicaid::Application.where(created_at: range).or(updated_at: range) + end + + def transfers + Aces::Transfer.where(created_at: range).or(updated_at: range) + end + + def inbound_transfers + Aces::InboundTransfer.where(created_at: range).or(updated_at: range) + end + + def checks + Aces::MecCheck.where(created_at: range).or(updated_at: range) + end end diff --git a/app/javascript/controllers/application_controller.js b/app/javascript/controllers/application_controller.js new file mode 100644 index 00000000..38c19a4e --- /dev/null +++ b/app/javascript/controllers/application_controller.js @@ -0,0 +1,60 @@ +import { Controller } from 'stimulus' +import StimulusReflex from 'stimulus_reflex' + +/* This is your ApplicationController. + * All StimulusReflex controllers should inherit from this class. + * + * Example: + * + * import ApplicationController from './application_controller' + * + * export default class extends ApplicationController { ... } + * + * Learn more at: https://docs.stimulusreflex.com + */ +export default class extends Controller { + connect () { + StimulusReflex.register(this) + } + + /* Application-wide lifecycle methods + * + * Use these methods to handle lifecycle concerns for the entire application. + * Using the lifecycle is optional, so feel free to delete these stubs if you don't need them. + * + * Arguments: + * + * element - the element that triggered the reflex + * may be different than the Stimulus controller's this.element + * + * reflex - the name of the reflex e.g. "Example#demo" + * + * error/noop - the error message (for reflexError), otherwise null + * + * reflexId - a UUID4 or developer-provided unique identifier for each Reflex + */ + + beforeReflex (element, reflex, noop, reflexId) { + // document.body.classList.add('wait') + } + + reflexSuccess (element, reflex, noop, reflexId) { + // show success message + } + + reflexError (element, reflex, error, reflexId) { + // show error message + } + + reflexHalted (element, reflex, error, reflexId) { + // handle aborted Reflex action + } + + afterReflex (element, reflex, noop, reflexId) { + // document.body.classList.remove('wait') + } + + finalizeReflex (element, reflex, noop, reflexId) { + // all operations have completed, animation etc is now safe + } +} diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js new file mode 100644 index 00000000..dcb15acf --- /dev/null +++ b/app/javascript/controllers/index.js @@ -0,0 +1,14 @@ +// Load all the controllers within this directory and all subdirectories. +// Controller files must be named *_controller.js. + +import { Application } from "stimulus" +import { definitionsFromContext } from "stimulus/webpack-helpers" +import StimulusReflex from 'stimulus_reflex' +import consumer from '../channels/consumer' +import controller from '../controllers/application_controller' + +const application = Application.start() +const context = require.context("controllers", true, /_controller\.js$/) +application.load(definitionsFromContext(context)) +StimulusReflex.initialize(application, { consumer, controller, isolate: true }) +StimulusReflex.debug = process.env.RAILS_ENV === 'development' diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js index 26530c6c..2747eca5 100644 --- a/app/javascript/packs/application.js +++ b/app/javascript/packs/application.js @@ -9,3 +9,5 @@ import "channels" Rails.start() Turbolinks.start() + +import "controllers" diff --git a/app/models/aces/inbound_transfer.rb b/app/models/aces/inbound_transfer.rb index e290466a..83276723 100644 --- a/app/models/aces/inbound_transfer.rb +++ b/app/models/aces/inbound_transfer.rb @@ -39,5 +39,8 @@ def to_event } end + def resubmittable? + payload.present? && ['Sent', 'Failed'].include?(result) + end end end diff --git a/app/operations/curam/check_payload.rb b/app/operations/curam/check_payload.rb index 9c98e103..dfd6a3a1 100644 --- a/app/operations/curam/check_payload.rb +++ b/app/operations/curam/check_payload.rb @@ -19,9 +19,9 @@ def call(id) protected - def find_transfer(application_id) - transfers = Aces::Transfer.where(application_identifier: application_id) - transfers.any? ? transfers.last : Failure(:no_transfers_found) + def find_transfer(transfer_id) + transfer = Aces::Transfer.find(transfer_id) + transfer || Failure(:no_transfers_found) end def build_check_request(transfer) diff --git a/app/reflexes/application_reflex.rb b/app/reflexes/application_reflex.rb new file mode 100644 index 00000000..4953b728 --- /dev/null +++ b/app/reflexes/application_reflex.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +class ApplicationReflex < StimulusReflex::Reflex + # Put application-wide Reflex behavior and callbacks in this file. + # + # Example: + # + # # If your ActionCable connection is: `identified_by :current_user` + # delegate :current_user, to: :connection + # + # Learn more at: https://docs.stimulusreflex.com/reflexes#reflex-classes +end diff --git a/app/reflexes/report_reflex.rb b/app/reflexes/report_reflex.rb new file mode 100644 index 00000000..d1a4e08f --- /dev/null +++ b/app/reflexes/report_reflex.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Update report pages based on user actions +class ReportReflex < ApplicationReflex + + def change_date + session_name = element.dataset[:session] + session[session_name] = Date.parse(element.value) + end + + def check_payload + Curam::CheckPayload.new.call(element.dataset[:id]) + end + + def resubmit_to_enroll + Transfers::ToEnroll.new.call(element.dataset[:payload], element.dataset[:id]) + end +end \ No newline at end of file diff --git a/app/reports/transfer_report.rb b/app/reports/transfer_report.rb index cfc6e6a9..15498b08 100644 --- a/app/reports/transfer_report.rb +++ b/app/reports/transfer_report.rb @@ -13,30 +13,54 @@ def self.run def self.run_report(start_on, end_on) timestamp = Time.zone.now.to_s range = start_on.beginning_of_day..end_on.end_of_day + + report_name = "transfer_report_#{timestamp}.csv" + FileUtils.touch(report_name) + CSV.open(report_name, "w") do |csv| + csv << headers + row = [range] + transfer_values(range) + + if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) + inbound_vals = inbound_transfer_values(range) + row.insert(2, inbound_vals[:total]) + row << inbound_vals[:successful] + row << inbound_vals[:failure] + end + + csv << row + end + end + + def self.headers + if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) + %w[DateRange Sent Received SentSuccesses SentFailures ReceivedSuccesses ReceivedFailures] + else + %w[DateRange Sent SentSuccesses SentFailures] + end + end + + def self.transfer_values(range) at_sent = Aces::Transfer.where(created_at: range).or(updated_at: range) at_sent_total = at_sent.count at_sent_successful = at_sent.where(failure: nil).count at_sent_failure = at_sent_total - at_sent_successful + [ + at_sent_total, + at_sent_successful, + at_sent_failure + ] + end + def self.inbound_transfer_values(range) at_received = Aces::InboundTransfer.where(created_at: range).or(updated_at: range) at_received_total = at_received.count at_received_successful = at_received.where(failure: nil).count at_received_failure = at_received_total - at_received_successful - - report_name = "transfer_report_#{timestamp}.csv" - FileUtils.touch(report_name) - CSV.open(report_name, "w") do |csv| - csv << %w[DateRange Sent Received SentSuccesses SentFailures ReceivedSuccesses ReceivedFailures] - csv << [ - range, - at_sent_total, - at_received_total, - at_sent_successful, - at_sent_failure, - at_received_successful, - at_received_failure - ] - end + { + total: at_received_total, + successful: at_received_successful, + failure: at_received_failure + } end end diff --git a/app/views/aces/inbound_transfers/show.html.erb b/app/views/aces/inbound_transfers/show.html.erb index 0a7c3772..cf667143 100644 --- a/app/views/aces/inbound_transfers/show.html.erb +++ b/app/views/aces/inbound_transfers/show.html.erb @@ -1,7 +1,7 @@

Transfer of <%= @transfer.external_id %> to Enroll

Updated At: <%= @transfer.created_at %>

Processed At: <%= @transfer.updated_at %>

-

Transfer Status: <%= @transfer.failure.nil? ? 'Success' : 'Failure' %>

+

Transfer Status: <%= @transfer.successful? ? 'Success' : 'Failure' %>

Ingestion Status: <%= @transfer.result %>

Application Identifier: <%= @transfer.application_identifier %>

Family Identifier: <%= @transfer.family_identifier %>

@@ -19,6 +19,9 @@ <%= @transfer.payload %> <% end %> - - -<%= link_to "See today's account transfers to Enroll", account_transfers_to_enroll_reports_path %> +<% unless @transfer.failure.blank? %> +

Failure Details:

+<%= @transfer.failure %> +<% end %> +
+<%= link_to "Sent Transfers Report", account_transfers_to_enroll_reports_path, class: 'btn btn-primary' %> diff --git a/app/views/aces/transfers/show.html.erb b/app/views/aces/transfers/show.html.erb index 7cf7be2f..548888b0 100644 --- a/app/views/aces/transfers/show.html.erb +++ b/app/views/aces/transfers/show.html.erb @@ -1,7 +1,7 @@ -

Transfer to <%= @transfer.service %>

+

Transfer to <%= @transfer.service.upcase %>

Created At: <%= @transfer.created_at %>

Processed At: <%= @transfer.updated_at %>

-

Transfer Status: <%= @transfer.failure.nil? ? 'Success' : 'Failure' %>

+

Transfer Status: <%= @transfer.successful? ? 'Success' : 'Failure' %>

Ingestion Status: <%= @transfer.callback_status %>

Application Identifier: <%= @transfer.application_identifier %>

Family Identifier: <%= @transfer.family_identifier %>

@@ -23,4 +23,9 @@ <%= raw(ap(JSON.parse(@transfer.callback_payload))) %> <% end %> -<%= link_to "See today's account transfers", account_transfers_reports_path %> \ No newline at end of file +<% unless @transfer.failure.blank? %> +

Failure Details:

+<%= @transfer.failure %> +<% end %> + +<%= link_to "Received Transfers Report", account_transfers_reports_path, class: 'btn btn-primary' %> diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index a3ba4d27..9795b326 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -11,8 +11,44 @@ -
+ +
<%= yield %> -
+ diff --git a/app/views/medicaid/applications/show.html.erb b/app/views/medicaid/applications/show.html.erb new file mode 100644 index 00000000..f5c97808 --- /dev/null +++ b/app/views/medicaid/applications/show.html.erb @@ -0,0 +1,32 @@ +

Determination of Application <%= @application.application_identifier %>

+

Created At: <%= @application.created_at %>

+

Processed At: <%= @application.updated_at %>

+ +

Application Request Payload:

+<%= raw(ap(JSON.parse(@application.application_request_payload))) %> +
+

Application Response Payload:

+<%= raw(ap(JSON.parse(@application.application_request_payload))) %> +
+

Medicaid Request Payload:

+<%= raw(ap(JSON.parse(@application.medicaid_request_payload))) %> +
+

Medicaid Response Payload:

+<%= raw(ap(JSON.parse(@application.medicaid_response_payload))) %> +
+

APTC Households

+<% @application.aptc_households.each do |household| %> + <% household.attributes.each do |attr_name, attr_value| %> + <%= attr_name %>: <%= attr_value %> +
+ <% end %> +<% end %> +
+

Other Factors

+<% if @application.other_factors == 'No other factors' %> + <%= @application.other_factors %> +<% else %> + <%= raw(ap(JSON.parse(@application.other_factors))) %> +<% end %> +
+<%= link_to "Determinations Report", medicaid_application_check_reports_path, class: 'btn btn-primary' %> diff --git a/app/views/reports/_date_range.html.erb b/app/views/reports/_date_range.html.erb new file mode 100644 index 00000000..f28027b1 --- /dev/null +++ b/app/views/reports/_date_range.html.erb @@ -0,0 +1,5 @@ + + + + +

<%= "as of #{Time.current.to_formatted_s(:time)} UTC" if @end_on.today? %>

\ No newline at end of file diff --git a/app/views/reports/account_transfers.html.erb b/app/views/reports/account_transfers.html.erb index db0aaad3..3ffc07b6 100644 --- a/app/views/reports/account_transfers.html.erb +++ b/app/views/reports/account_transfers.html.erb @@ -1,6 +1,6 @@ -

Account Transfers To <%= @transfers.first&.service.upcase if @transfers.any? %>

-

<%= @range %>

- +

Account Transfers To <%= MedicaidGatewayRegistry[:transfer_service].item.upcase %>

+<%= render partial: "date_range", locals: {start_on: @start_on, end_on: @end_on, session_name: "atp_"} %> +
@@ -12,11 +12,19 @@ <% @transfers.each do |transfer| %> - + - + <% end %> diff --git a/app/views/reports/account_transfers_to_enroll.html.erb b/app/views/reports/account_transfers_to_enroll.html.erb index 5096a249..6965322d 100644 --- a/app/views/reports/account_transfers_to_enroll.html.erb +++ b/app/views/reports/account_transfers_to_enroll.html.erb @@ -1,6 +1,6 @@

Account Transfers To Enroll

-

<%= @range %>

-
Transfer Status Created At
<%= transfer.failure.nil? ? 'Sucess' : 'Failure' %> <%= transfer.failure unless transfer.failure.nil? %><%= transfer.successful? ? "Success" : "Failure" %> <%= transfer.created_at %> <%= transfer.family_identifier %> <%= transfer.application_identifier %><%= transfer.callback_status %> + <% if transfer.service =="curam" && transfer.callback_status.blank? %> +
+ +
+ <% else %> + <%= transfer.callback_status %> + <% end %> +
<%= link_to "details", transfer, class: 'btn btn-primary' %>
+<%= render partial: "date_range", locals: {start_on: @start_on, end_on: @end_on, session_name: "atp_"} %> +
@@ -13,13 +13,20 @@ <% @transfers.each do |transfer| %> - + - + <% end %> diff --git a/app/views/reports/events.html.erb b/app/views/reports/events.html.erb new file mode 100644 index 00000000..263e7579 --- /dev/null +++ b/app/views/reports/events.html.erb @@ -0,0 +1,20 @@ +

Event Log

+<%= render partial: "date_range", locals: {start_on: @start_on, end_on: @end_on, session_name: "atp_"} %> +
Transfer Status Creation Date
<%= transfer.failure.nil? ? 'Success' : 'Failure' %><%= transfer.successful? ? "Success" : "Failure" %> <%= transfer.created_at %> <%= transfer.external_id %> <%= transfer.family_identifier %> <%= transfer.application_identifier %> <%= transfer.result %><%= " - #{transfer.failure}" unless transfer.failure.nil? %><%= link_to "Details", transfer, class: 'btn btn-primary' %> + <%= link_to "Details", transfer, class: 'btn btn-primary' %> + <% if MedicaidGatewayRegistry.feature_enabled?(:resubmit_to_enroll) && transfer.resubmittable? %> +
+ +
+ <% end %> +
+ + + + + + + + <% @events.each do |event| %> + + + + + + + <% end %> + +
StatusTypeCreated AtApplication Identifier
<%= event[:success] ? "Success" : "Failure" %><%= event[:type] %><%= event[:created_at] %><%= event[:app_id] %>
\ No newline at end of file diff --git a/app/views/reports/mec_checks.html.erb b/app/views/reports/mec_checks.html.erb index 63d391e3..6b26dc98 100644 --- a/app/views/reports/mec_checks.html.erb +++ b/app/views/reports/mec_checks.html.erb @@ -1,6 +1,6 @@

Mec Checks

-

<%= @range %>

- +<%= render partial: "date_range", locals: {start_on: @start_on, end_on: @end_on, session_name: "mc_sent_"} %> +
@@ -11,7 +11,7 @@ <% @checks.each do |check| %> - +
Result Application ID
<%= check.failure.nil? ? "Success" : "Failure" %><%= check.successful? ? "Success" : "Failure" %> <%= check.application_identifier %> <%= check.family_identifier %> diff --git a/app/views/reports/medicaid_application_check.html.erb b/app/views/reports/medicaid_application_check.html.erb index 3dc11de7..d8bfcf80 100644 --- a/app/views/reports/medicaid_application_check.html.erb +++ b/app/views/reports/medicaid_application_check.html.erb @@ -1,6 +1,6 @@

Determinations

-

<%= @range %>

- +<%= render partial: "date_range", locals: {start_on: @start_on, end_on: @end_on, session_name: 'ma_'} %> +
@@ -14,13 +14,16 @@ <% @applications.each do |application| %> - - - - - - + + + + + + <% end %> -
Application Identifer
<%= application.application_identifier %><%= application.medicaid_request_payload %><%= application.medicaid_response_payload %><%= application.application_request_payload %><%= application.application_response_payload %><%= application.other_factors %> + <%= application.application_identifier %> + <%= link_to 'Details', application, class: 'btn btn-primary' %> +
<%= application.medicaid_request_payload %>
<%= application.medicaid_response_payload %>
<%= application.application_request_payload %>
<%= application.application_response_payload %>
<%= application.other_factors %>
\ No newline at end of file +
diff --git a/app/views/reports/transfer_summary.html.erb b/app/views/reports/transfer_summary.html.erb index e81503c9..973b0c92 100644 --- a/app/views/reports/transfer_summary.html.erb +++ b/app/views/reports/transfer_summary.html.erb @@ -1,24 +1,34 @@

Account Transfer Summary

-

<%= @range %>

- +<%= render partial: "date_range", locals: {start_on: @start_on, end_on: @end_on, session_name: "atp_"} %> +
- + <% if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) %> + + <% end %> - - + <% if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) %> + + + <% end %> - + <% if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) %> + + <% end %> - - + <% if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) %> + + + <% end %>
SentReceivedReceivedSent Successes Sent FailuresReceived SuccessesReceived FailuresReceived SuccessesReceived Failures
<%= @at_sent_total %><%= @at_received_total %><%= @at_received_total %><%= @at_sent_successful %> <%= @at_sent_failure %><%= @at_received_successful %><%= @at_received_failure %><%= @at_received_successful %><%= @at_received_failure %>
-<%= link_to "Received Details", account_transfers_to_enroll_reports_path(start_on: @start_on, end_on: @end_on), class: 'btn btn-primary' %> -<%= link_to "Sent Details", account_transfers_reports_path(start_on: @start_on, end_on: @end_on), class: 'btn btn-primary mx-2' %> \ No newline at end of file +<% if MedicaidGatewayRegistry.feature_enabled?(:transfer_to_enroll) %> + <%= link_to "Received Details", account_transfers_to_enroll_reports_path, class: 'btn btn-primary' %> +<% end %> +<%= link_to "Sent Details", account_transfers_reports_path, class: 'btn btn-primary mx-2' %> \ No newline at end of file diff --git a/app/views/transfers/show.html.erb b/app/views/transfers/show.html.erb deleted file mode 100644 index aec12865..00000000 --- a/app/views/transfers/show.html.erb +++ /dev/null @@ -1 +0,0 @@ -<%= @transfer.inspect %> \ No newline at end of file diff --git a/components/mitc_service/Gemfile b/components/mitc_service/Gemfile index 7f1e455c..b979c331 100644 --- a/components/mitc_service/Gemfile +++ b/components/mitc_service/Gemfile @@ -9,8 +9,8 @@ gemspec # To use a debugger # gem 'byebug', group: [:development, :test] -gem 'aca_entities', git: 'https://github.com/ideacrew/aca_entities.git', branch: 'release_0.10.0' -gem 'event_source', git: 'https://github.com/ideacrew/event_source.git', branch: 'release_0.5.5' +gem 'aca_entities', git: 'https://github.com/ideacrew/aca_entities.git', branch: 'trunk' +gem 'event_source', git: 'https://github.com/ideacrew/event_source.git', branch: 'trunk' group :development, :test do gem "rspec-rails" diff --git a/components/mitc_service/Gemfile.lock b/components/mitc_service/Gemfile.lock index ade8bd7c..a9fcede0 100644 --- a/components/mitc_service/Gemfile.lock +++ b/components/mitc_service/Gemfile.lock @@ -1,7 +1,7 @@ GIT remote: https://github.com/ideacrew/aca_entities.git - revision: acccd54c96e8d9ef48e239a56ecd2b6536e88ff2 - branch: release_0.10.0 + revision: abd4c4e4bed30c5c1008479545df41d4f9e494b9 + branch: trunk specs: aca_entities (0.9.0) deep_merge @@ -17,11 +17,11 @@ GIT GIT remote: https://github.com/ideacrew/event_source.git - revision: 3d69618c16fbbe09912eeba097aedac47d1abc15 - branch: release_0.5.5 + revision: 29393ebb04df8f57ccb536da4635087c8c8bde0b + branch: trunk specs: event_source (0.5.5) - bunny (~> 2.14) + bunny (>= 2.14) deep_merge (~> 1.2.0) dry-events (~> 0.3) dry-inflector (~> 0.2) @@ -194,7 +194,7 @@ GEM erubi (1.10.0) et-orbi (1.2.5) tzinfo - ethon (0.14.0) + ethon (0.15.0) ffi (>= 1.15.0) factory_bot (6.2.0) activesupport (>= 5.0.0) @@ -214,7 +214,7 @@ GEM faraday-excon (1.1.0) faraday-net_http (1.0.1) faraday-net_http_persistent (1.2.0) - faraday_middleware (1.1.0) + faraday_middleware (1.2.0) faraday (~> 1.0) ffi (1.15.4) fugit (1.5.2) @@ -316,7 +316,7 @@ GEM rbnacl (7.1.1) ffi rbtree (0.4.4) - redis (4.4.0) + redis (4.5.1) redis-namespace (1.8.1) redis (>= 3.0.4) regexp_parser (2.1.1) @@ -372,7 +372,7 @@ GEM ruby2_keywords (0.0.5) rufus-scheduler (3.6.0) fugit (~> 1.1, >= 1.1.6) - set (1.0.1) + set (1.0.2) sinatra (2.1.0) mustermann (~> 1.0) rack (~> 2.2) diff --git a/config/cable.yml b/config/cable.yml index 5c78fd8e..87325c7b 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -1,10 +1,12 @@ development: - adapter: async + adapter: redis + url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + channel_prefix: medicaid_gateway_development test: adapter: test production: adapter: redis - url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> + url: redis://<%= ENV['REDIS_HOST_MEDICAID_GATEWAY'] %>:6379/1 channel_prefix: medicaid_gateway_production diff --git a/config/client_config/dc/system/config/templates/features/features.yml b/config/client_config/dc/system/config/templates/features/features.yml index cc7d24f5..349f240c 100644 --- a/config/client_config/dc/system/config/templates/features/features.yml +++ b/config/client_config/dc/system/config/templates/features/features.yml @@ -15,3 +15,5 @@ registry: is_enabled: false - key: :mec_check is_enabled: false + - key: :resubmit_to_enroll + is_enabled: false diff --git a/config/client_config/me/system/config/templates/features/features.yml b/config/client_config/me/system/config/templates/features/features.yml index c8486e8a..d93b8c37 100644 --- a/config/client_config/me/system/config/templates/features/features.yml +++ b/config/client_config/me/system/config/templates/features/features.yml @@ -15,3 +15,5 @@ registry: is_enabled: true - key: :mec_check is_enabled: true + - key: :resubmit_to_enroll + is_enabled: false \ No newline at end of file diff --git a/config/environments/development.rb b/config/environments/development.rb index 8d1b9afa..5d7b29dc 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -3,6 +3,7 @@ require 'active_support/core_ext/integer/time' Rails.application.configure do + config.session_store :cache_store # Settings specified here will take precedence over those in config/application.rb. # In the development environment your application's code is reloaded any time diff --git a/config/environments/test.rb b/config/environments/test.rb index 9a1977f2..fc5b9da9 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -26,8 +26,8 @@ # Show full error reports and disable caching. config.consider_all_requests_local = true - config.action_controller.perform_caching = false - config.cache_store = :null_store + config.action_controller.perform_caching = true + config.cache_store = :memory_store # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false diff --git a/config/initializers/stimulus_reflex.rb b/config/initializers/stimulus_reflex.rb new file mode 100644 index 00000000..aaea153e --- /dev/null +++ b/config/initializers/stimulus_reflex.rb @@ -0,0 +1,34 @@ +# frozen_string_literal: true + +StimulusReflex.configure do |config| + # Enable/disable exiting / warning when the sanity checks fail options: + # `:exit` or `:warn` or `:ignore` + + # config.on_failed_sanity_checks = :exit + + # Override the parent class that the StimulusReflex ActionCable channel inherits from + + # config.parent_channel = "ApplicationCable::Channel" + + # Customize server-side Reflex logging format, with optional colorization: + # Available tokens: session_id, session_id_full, reflex_info, operation, reflex_id, reflex_id_full, + # mode, selector, operation_counter, connection_id, connection_id_full, timestamp + + # Available colors: red, green, yellow, blue, magenta, cyan, white + # You can also use attributes from your ActionCable Connection's identifiers that resolve to valid ActiveRecord models + # eg. if your connection is `identified_by :current_user` and your User model + # has an email attribute, you can access r.email (it will display `-` if the user isn't logged in) + # Learn more at: https://docs.stimulusreflex.com/troubleshooting#stimulusreflex-logging + + # config.logging = proc { "[#{session_id}] #{operation_counter.magenta} #{reflex_info.green} -> #{selector.cyan} via #{mode} Morph + # (#{operation.yellow})" } + + # Optimized for speed, StimulusReflex doesn't enable Rack middleware by default. + # If you are using Page Morphs and your app uses Rack middleware to rewrite part of the request path, + # you must enable those middleware modules in StimulusReflex. + # + # Learn more about registering Rack middleware in Rails here: https://guides.rubyonrails.org/rails_on_rack.html#configuring-middleware-stack + + # config.middleware.use FirstRackMiddleware + # config.middleware.use SecondRackMiddleware +end diff --git a/config/routes.rb b/config/routes.rb index d0e91199..d8804d40 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true Rails.application.routes.draw do - # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html + + root 'reports#events' + namespace :aces do resource :publishing_connectivity_tests, only: [:new, :create] resources :inbound_transfers, only: [:show] @@ -16,6 +18,10 @@ end end + namespace :medicaid do + resources :applications, only: [:show] + end + resources :reports, only: [] do collection do get 'medicaid_applications' @@ -24,6 +30,7 @@ get 'transfer_summary' get 'medicaid_application_check' get 'mec_checks' + get 'events' end end diff --git a/package.json b/package.json index 7c367117..34e3cc8c 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "@rails/actioncable": "^6.0.0", "@rails/ujs": "^6.0.0", "@rails/webpacker": "5.4.3", + "stimulus": "^3.0.1", + "stimulus_reflex": "3.4.1", "turbolinks": "^5.2.0", "webpack": "^4.46.0", "webpack-cli": "^3.3.12" diff --git a/spec/domain/operations/curam/check_payload_spec.rb b/spec/domain/operations/curam/check_payload_spec.rb index dca35d67..480ae268 100644 --- a/spec/domain/operations/curam/check_payload_spec.rb +++ b/spec/domain/operations/curam/check_payload_spec.rb @@ -13,7 +13,7 @@ let(:id) {"SBM123"} - let!(:transfer) { FactoryBot.create(:transfer, application_identifier: id) } + let!(:transfer) { FactoryBot.create(:transfer, id: id) } let(:response_body) do " @@ -53,13 +53,13 @@ end it "initally the transfer should not have a callback status" do - updated_transfer = Aces::Transfer.where(application_identifier: id).first + updated_transfer = Aces::Transfer.find(id) expect(updated_transfer.callback_status).to_not eq "Federal Exchange Inbound Error" end it "calling the check payload should update the transfer callback status" do operation.call(id) - updated_transfer = Aces::Transfer.where(application_identifier: id).first + updated_transfer = Aces::Transfer.find(id) expect(updated_transfer.callback_status).to eq "Federal Exchange Inbound Error" end diff --git a/spec/requests/reports_spec.rb b/spec/requests/reports_spec.rb index e5729b1b..25baade8 100644 --- a/spec/requests/reports_spec.rb +++ b/spec/requests/reports_spec.rb @@ -7,6 +7,45 @@ DatabaseCleaner.clean end + describe "GET /reports/events" do + before do + create :transfer + create :inbound_transfer + create :mec_check + create :application + end + + it "generates Event Report" do + visit '/reports/events' + expect(page).to have_content("Event Log") + end + + it "shows the previous 24 hours without params" do + create :transfer, created_at: 2.days.ago, updated_at: 2.days.ago, application_identifier: "100745" + visit '/reports/events' + + expect(page).to_not have_content("100745") + end + + it "accepts and uses date params" do + old_transfer = create :transfer, created_at: 1.day.ago, updated_at: 1.day.ago + start_on = 2.days.ago.strftime('%m/%d/%Y') + visit "/reports/events?start_on=#{start_on}" + + expect(page).to have_content(old_transfer.application_identifier) + end + + # TODO: test date input (Stimulus Reflex) + # it "user input changes date range" do + # old_transfer = create :transfer, created_at: 1.day.ago, updated_at: 1.day.ago + # visit '/reports/events' + # expect(page).not_to have_content(old_transfer.application_identifier) + # start_on = 3.days.ago.strftime('%Y-%m-%d') + # fill_in "input#start_on", with: start_on + # expect(page).to have_content(old_transfer.application_identifier) + # end + end + describe "GET /reports/medicaid_applications" do before { create :application } @@ -79,6 +118,30 @@ end end + describe "GET /reports/account_transfers_to_enroll" do + before { create :inbound_transfer } + + it "generates transfer report" do + visit '/reports/account_transfers_to_enroll' + expect(page).to have_content("Account Transfers To Enroll") + end + + it "shows the previous 24 hours without params" do + create :inbound_transfer, created_at: 2.days.ago, updated_at: 2.days.ago, application_identifier: "100745" + visit '/reports/account_transfers_to_enroll' + + expect(page).to_not have_content("100745") + end + + it "accepts and uses date params" do + old_transfer = create :inbound_transfer, created_at: 1.day.ago, updated_at: 1.day.ago + start_on = 2.days.ago.strftime('%m/%d/%Y') + visit "/reports/account_transfers_to_enroll?start_on=#{start_on}" + + expect(page).to have_content(old_transfer.application_identifier) + end + end + describe "GET /reports/mec_checks" do it "generates mec check report" do diff --git a/system/config/templates/features/features.yml b/system/config/templates/features/features.yml index c8486e8a..d93b8c37 100644 --- a/system/config/templates/features/features.yml +++ b/system/config/templates/features/features.yml @@ -15,3 +15,5 @@ registry: is_enabled: true - key: :mec_check is_enabled: true + - key: :resubmit_to_enroll + is_enabled: false \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index be90641c..d7743f2f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1045,6 +1045,16 @@ resolved "https://registry.yarnpkg.com/@csstools/convert-colors/-/convert-colors-1.4.0.tgz#ad495dc41b12e75d588c6db8b9834f08fa131eb7" integrity sha512-5a6wqoJV/xEdbRNKVo6I4hO3VjyDq//8q2f9I6PBAvMesJHFauXDorcNCsr9RzvsZnaWi5NYCcfyqP1QeFHFbw== +"@hotwired/stimulus-webpack-helpers@^1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus-webpack-helpers/-/stimulus-webpack-helpers-1.0.1.tgz#4cd74487adeca576c9865ac2b9fe5cb20cef16dd" + integrity sha512-wa/zupVG0eWxRYJjC1IiPBdt3Lruv0RqGN+/DTMmUWUyMAEB27KXmVY6a8YpUVTM7QwVuaLNGW4EqDgrS2upXQ== + +"@hotwired/stimulus@^3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@hotwired/stimulus/-/stimulus-3.0.1.tgz#141f15645acaa3b133b7c247cad58ae252ffae85" + integrity sha512-oHsJhgY2cip+K2ED7vKUNd2P+BEswVhrCYcJ802DSsblJFv7mPFVk3cQKvm2vHgHeDVdnj7oOKrBbzp1u8D+KA== + "@npmcli/move-file@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.1.2.tgz#1a82c3e372f7cae9253eb66d72543d6b8685c674" @@ -1053,6 +1063,11 @@ mkdirp "^1.0.4" rimraf "^3.0.2" +"@rails/actioncable@>= 6.0": + version "6.1.4" + resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.1.4.tgz#c3c5a9f8302c429af9722b6c50ab48049016d2a3" + integrity sha512-0LmSKJTuo2dL6BQ+9xxLnS9lbkyfz2mBGeBnQ2J7o9Bn0l0q+ZC6VuoZMZZXPvABI4QT7Nfknv5WhfKYL+boew== + "@rails/actioncable@^6.0.0": version "6.1.3" resolved "https://registry.yarnpkg.com/@rails/actioncable/-/actioncable-6.1.3.tgz#c8a67ec4d22ecd6931f7ebd98143fddbc815419a" @@ -1810,6 +1825,13 @@ bytes@3.1.0: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== +"cable_ready@>= 4.5.0": + version "4.5.0" + resolved "https://registry.yarnpkg.com/cable_ready/-/cable_ready-4.5.0.tgz#1207218dd16934d12addfbd34c26ead853570672" + integrity sha512-9bom1DuYe1teBdRckgKWjg+rWRLWrkOvkhzlXkhb33X+Pfu/QK9e4vGk6hGK9PVKVr0SYZC41dByFGknW4spLg== + dependencies: + morphdom "^2.6.1" + cacache@^12.0.2: version "12.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" @@ -4404,6 +4426,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4: resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== +morphdom@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/morphdom/-/morphdom-2.6.1.tgz#e868e24f989fa3183004b159aed643e628b4306e" + integrity sha512-Y8YRbAEP3eKykroIBWrjcfMw7mmwJfjhqdpSvoqinu8Y702nAwikpXcNFDiIkyvfCLxLM9Wu95RZqo4a9jFBaA== + move-concurrently@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" @@ -6386,6 +6413,22 @@ static-extend@^0.1.1: resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= +stimulus@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/stimulus/-/stimulus-3.0.1.tgz#370e3054eb3b8068904af1888949821255d375d3" + integrity sha512-73uZG5E5bwH7W2BldieTXg4yJuEmOfIHgtO/aqwU0JkWNjwY75ZaoOAD2EEPvi5AK43N9adEeOQOmlgWf59HOg== + dependencies: + "@hotwired/stimulus" "^3.0.1" + "@hotwired/stimulus-webpack-helpers" "^1.0.0" + +stimulus_reflex@3.4.1: + version "3.4.1" + resolved "https://registry.yarnpkg.com/stimulus_reflex/-/stimulus_reflex-3.4.1.tgz#2606aee3b2911b5939d68f65a75262fe3c626204" + integrity sha512-YbFcuE4HndNe9RBQvF/Vu+7GDt0zLGdhQTXuGfLDVti1qggPG3kPgV1YBZ9volzBTGUmLp2PQbxG9j5AIyYp5A== + dependencies: + "@rails/actioncable" ">= 6.0" + cable_ready ">= 4.5.0" + stream-browserify@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"