automate employer setup import from word and manual entry working

This commit is contained in:
Jason Jordan
2025-12-03 11:42:15 -05:00
parent 3fbece7da6
commit 78ce415b94
44 changed files with 1012 additions and 339 deletions
+2
View File
@@ -75,3 +75,5 @@ yarn-debug.log*
/app/assets/builds/* /app/assets/builds/*
!/app/assets/builds/.keep !/app/assets/builds/.keep
/mssql-data
+2
View File
@@ -82,3 +82,5 @@ gem 'tiny_tds'
gem 'devise' gem 'devise'
gem 'pundit' gem 'pundit'
gem "tailwindcss-rails" gem "tailwindcss-rails"
gem 'docx'
gem 'rubyzip'
+5
View File
@@ -115,6 +115,9 @@ GEM
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.6.2) diff-lcs (1.6.2)
docx (0.10.0)
nokogiri (~> 1.13, >= 1.13.0)
rubyzip (>= 2.0, < 4)
drb (2.2.3) drb (2.2.3)
erb (5.1.3) erb (5.1.3)
erubi (1.13.1) erubi (1.13.1)
@@ -389,6 +392,7 @@ DEPENDENCIES
bundler-audit bundler-audit
capybara capybara
devise devise
docx
importmap-rails importmap-rails
jbuilder jbuilder
pry-rails pry-rails
@@ -400,6 +404,7 @@ DEPENDENCIES
rubocop-rails rubocop-rails
rubocop-rails-omakase rubocop-rails-omakase
rubocop-rspec rubocop-rspec
rubyzip
selenium-webdriver selenium-webdriver
sprockets-rails sprockets-rails
stimulus-rails stimulus-rails
+18
View File
@@ -5,14 +5,32 @@
--color-deepcove: #04153E; --color-deepcove: #04153E;
/* medium dark blue */ /* medium dark blue */
--color-bluetang: #2A4B6F; --color-bluetang: #2A4B6F;
/* medium dark blue */
--color-bluetang-tinted: #223C59;
/* bright blue */ /* bright blue */
--color-atmosphere: #0096E0; --color-atmosphere: #0096E0;
/* bright blue */
--color-atmosphere-tinted: #007AB8;
/* light blue */ /* light blue */
--color-bluemana: #6AC8F1; --color-bluemana: #6AC8F1;
/* light blue */
--color-bluemana-tinted: #44BBEE;
/* cobalt blue */
--color-cobalt: #0047AB;
/* cobalt blue */
--color-cobalt-tinted: #003B8F;
/* platinum */ /* platinum */
--color-platinum: #E0E0E0; --color-platinum: #E0E0E0;
/* copper */ /* copper */
--color-copper: #B06E30; --color-copper: #B06E30;
/* copper */
--color-copper-tinted: #905A27;
/* bronze */ /* bronze */
--color-bronze: #D38F4A; --color-bronze: #D38F4A;
/* bronze */
--color-bronze-tinted: #C57A30;
/* oxidized copper/bronze green-blue */
--color-verdigris: #588288;
/* oxidized copper/bronze green-blue */
--color-verdigris-tinted: #496A6F;
} }
+140 -105
View File
@@ -1,20 +1,36 @@
class EmployerSetupController < ApplicationController class EmployerSetupController < ApplicationController
def new def new
# session.delete(:employer_setup_data)
session.clear()
# puts "Start"
# puts session[:employer_setup_data]
if session[:employer_setup_data].blank?
session[:employer_setup_data] = {}
end
session[:employer_setup_data]['current_step'] = 'network_exceptions'
session[:employer_setup_data]['pl_plan_key'] = 82
@top_form = EmployerSetupForm.new(session[:employer_setup_data]) @top_form = EmployerSetupForm.new(session[:employer_setup_data])
case @top_form.current_step if @top_form.current_step != 'summary'
when 'general_information' @form = form_for_step
@form = EmployerSetupGeneralInformationForm.new(session[:employer_setup_data]&.dig('general_information_data')) else
when 'plans'
@form = EmployerSetupPlansForm.new(session[:employer_setup_data]&.dig('plans_data'))
when 'network_exceptions'
@form = EmployerSetupNetworkExceptionsForm.new(session[:employer_setup_data]&.dig('network_exceptions_data'))
when 'summary'
@form = @top_form @form = @top_form
end end
# case @top_form.current_step
# when 'general_information'
# @form = EmployerSetupGeneralInformationForm.new(session[:employer_setup_data]&.dig('general_information_data'))
# when 'plans'
# @form = EmployerSetupPlansForm.new(session[:employer_setup_data]&.dig('plans_data'))
# when 'network_exceptions'
# @form = EmployerSetupNetworkExceptionsForm.new(session[:employer_setup_data]&.dig('network_exceptions_data'))
# when 'summary'
# @form = @top_form
# end
render @top_form.current_step_view render @top_form.current_step_view
end end
def create def create
# puts session[:employer_setup_data]
@top_form = EmployerSetupForm.new(session[:employer_setup_data]) @top_form = EmployerSetupForm.new(session[:employer_setup_data])
if @top_form.current_step != 'summary' if @top_form.current_step != 'summary'
if process_step(@top_form.current_step) if process_step(@top_form.current_step)
@@ -32,43 +48,43 @@ class EmployerSetupController < ApplicationController
end end
end end
case @top_form.current_step # case @top_form.current_step
when 'general_information' # when 'general_information'
@form = EmployerSetupGeneralInformationForm.new(general_information_params) # @form = EmployerSetupGeneralInformationForm.new(general_information_params)
if @form.valid? # if @form.valid?
session[:employer_setup_data]['general_information_data'] = general_information_params # session[:employer_setup_data]['general_information_data'] = general_information_params
session[:employer_setup_data]['current_step'] = @top_form.next_step # session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path # redirect_to new_employer_setup_path
else # else
render @top_form.current_step_view # render @top_form.current_step_view
end # end
when 'plans' # when 'plans'
@form = EmployerSetupPlansForm.new(plans_params) # @form = EmployerSetupPlansForm.new(plans_params)
if @form.valid? # if @form.valid?
session[:employer_setup_data]['plans_data'] = plans_params # session[:employer_setup_data]['plans_data'] = plans_params
session[:employer_setup_data]['current_step'] = @top_form.next_step # session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path # redirect_to new_employer_setup_path
else # else
render @top_form.current_step_view # render @top_form.current_step_view
end # end
when 'network_exceptions' # when 'network_exceptions'
@form = EmployerSetupNetworkExceptionsForm.new(network_exceptions_params) # @form = EmployerSetupNetworkExceptionsForm.new(network_exceptions_params)
if @form.valid? # if @form.valid?
session[:employer_setup_data]['network_exceptions_data'] = network_exceptions_params # session[:employer_setup_data]['network_exceptions_data'] = network_exceptions_params
session[:employer_setup_data]['current_step'] = @top_form.next_step # session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path # redirect_to new_employer_setup_path
else # else
render @top_form.current_step_view # render @top_form.current_step_view
end # end
when 'summary' # when 'summary'
@form = EmployerSetupForm.new(session[:employer_setup_data]) # @form = EmployerSetupForm.new(session[:employer_setup_data])
if @form.save # if @form.save
session.delete(:employer_setup_data) # session.delete(:employer_setup_data)
redirect_to root_path, notice: "Employer setup successfully!" # redirect_to root_path, notice: "Employer setup successfully!"
else # else
render @top_form.current_step_view # render @top_form.current_step_view
end # end
end # end
end end
def update def update
@@ -85,70 +101,89 @@ class EmployerSetupController < ApplicationController
private private
def general_information_params # def general_information_params
params.require(:employer_setup_general_information_form).permit( # params.require(:employer_setup_general_information_form).permit(
:name, # :name,
:employer_logo, # :employer_logo,
:group_number, # :group_number,
:dental, # :dental,
:pl_plan_key, # :pl_plan_key,
:effect_date, # :effect_date,
:number_of_plans, # :number_of_plans,
:network, # :network,
:number_of_additional_network_logos # :number_of_additional_network_logos
) # )
end # end
def plans_params # def plans_params
params.require(:employer_setup_plans_form).permit( # params.require(:employer_setup_plans_form).permit(
plans: permited_plans_keys, # plans: permited_plans_keys,
benefit_descs: benefit_sequence_keys # benefit_descs: benefit_sequence_keys
) # )
end # end
def network_exceptions_params # def network_exceptions_params
params.require(:employer_setup_network_exceptions_form).permit( # params.require(:employer_setup_network_exceptions_form).permit(
network_exceptions: [:network_logo, exceptions: [:type, :value]], # network_exceptions: [:network_logo, exceptions: [:type, :value]],
) # )
# end
def form_for_step
step_name = @top_form.current_step
form_method = "EmployerSetup#{step_name.camelize}Form".constantize
form_method.new()
end end
def process_step(step_name) def process_step(step_name)
form_name = "employer_setup_#{step_name}_form".camelize.constantize @form_method = "EmployerSetup#{step_name.camelize}Form".constantize
form_params_name = "#{step_name}_params".to_sym session_data_name = "#{step_name}_data"
allowed_params = [:general_information_params, :plans_params, :network_exceptions_params] puts "1--------------params----"
if allowed_params.include?(form_params_name) puts params
form_params = send(form_params_name) puts "8--------------session----"
@form = form_name.new(form_params) puts session[:employer_setup_data]
if @form.valid? @form = @form_method.new(params)
session[:employer_setup_data]["#{step_name}_data"] = form_params if @form.pl_plan_key.blank?
true @form.pl_plan_key = session[:employer_setup_data]['pl_plan_key']
else
false
end
end end
false if @form.valid? && @form.save
end pl_plan_key = @top_form.pl_plan_key || @form.pl_plan_key
session[:employer_setup_data] = {current_step: step_name, pl_plan_key: pl_plan_key}
# form_fields = @form.attributes.merge!(global_params(step_name))
# session[:employer_setup_data][session_data_name] = form_fields
# session[:employer_setup_data].merge!(global_params(step_name))
# puts session[:employer_setup_data][session_data_name]
session[:employer_setup_data]['current_step'] = @top_form.next_step true
redirect_to new_employer_setup_path
else else
render @top_form.current_step_view false
end end
end end
when 'general_information' def step_params(step_name)
@form = EmployerSetupGeneralInformationForm.new(general_information_params) form_name_sym = "employer_setup_#{step_name}_form".to_sym
if @form.valid? params.require(form_name_sym).permit(@form_method.permitted_params)
session[:employer_setup_data]['general_information_data'] = general_information_params end
session[:employer_setup_data]['current_step'] = @top_form.next_step
redirect_to new_employer_setup_path def global_params(step_name)
else form_name_sym = "employer_setup_#{step_name}_form".to_sym
render @top_form.current_step_view params.require(form_name_sym).permit(EmployerSetupForm.permitted_params)
end end
# def process_step(step_name)
# form_name = "employer_setup_#{step_name}_form".camelize.constantize
# form_params_name = "#{step_name}_params".to_sym
# allowed_params = [:general_information_params, :plans_params, :network_exceptions_params]
# if allowed_params.include?(form_params_name)
# form_params = send(form_params_name)
# @form = form_name.new(form_params)
# if @form.valid?
# session[:employer_setup_data]["#{step_name}_data"] = form_params
# true
# else
# false
# end
# end
# false
# end
# def employer_setup_params # def employer_setup_params
# params.require(:employer_setup_form).permit( # params.require(:employer_setup_form).permit(
@@ -167,13 +202,13 @@ class EmployerSetupController < ApplicationController
# ) # )
# end # end
def benefit_sequence_keys # def benefit_sequence_keys
(1..14).map { |i| i.to_s.to_sym } # (1..14).map { |i| i.to_s.to_sym }
end # end
def permited_plans_keys # def permited_plans_keys
benefit_sequence_keys.push(:plan_id) # benefit_sequence_keys.push(:plan_id)
end # end
# def plans_params # def plans_params
# plans_keys = params[:plans]&.keys || [] # plans_keys = params[:plans]&.keys || []
@@ -35,7 +35,7 @@ class IdCardBenefitsTemplatesController < ApplicationController
@id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits @id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits
end end
def get_templates_benefits def get_template_benefits
@id_card_benefits = IdCardBenefitsTemplate.find(params[:id]).id_card_benefits @id_card_benefits = IdCardBenefitsTemplate.find(params[:id]).id_card_benefits
render json: @id_card_benefits.as_json render json: @id_card_benefits.as_json
end end
+44 -21
View File
@@ -5,19 +5,33 @@ class EmployerSetupForm
FIRST_STEP = "general_information" FIRST_STEP = "general_information"
attribute :current_step, :string, default: FIRST_STEP attribute :current_step, :string, default: FIRST_STEP
attribute :general_information_data attribute :pl_plan_key, :string
attribute :plans_data
attribute :network_exceptions_data
def initialize(params = {}) def initialize(params = {})
# if params.present?
# params = permitted_params(params)
# end
super(params)
unless self.steps.first == FIRST_STEP unless self.steps.first == FIRST_STEP
raise StepMisalignmentError, "FIRST_STEP does not match first entry in steps" raise StepMisalignmentError, "FIRST_STEP does not match first entry in steps"
end end
@general_information_data = EmployerSetupGeneralInformationForm.new(attributes[:general_information_data]) # @general_information_data = EmployerSetupGeneralInformationForm.new(attributes[:general_information_data])
@plans_data = EmployerSetupPlansForm.new(attributes[:plans_data]) # @plans_data = EmployerSetupPlansForm.new(attributes[:plans_data])
@network_exceptions_data = EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data]) # @network_exceptions_data = EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data])
end end
# def self.form_session_init
# {
# general_information_data: {},
# plans_data: {},
# network_exceptions_data: {}
# }
# end
# def steps
# %w[general_information plans network_exceptions summary]
# end
def steps def steps
%w[general_information plans network_exceptions summary] %w[general_information plans network_exceptions summary]
end end
@@ -29,11 +43,7 @@ class EmployerSetupForm
def next_step def next_step
index = steps.index(current_step) index = steps.index(current_step)
if index && index < steps.length - 1 if index && index < steps.length - 1
if steps[index + 1] == 'network_exceptions' && general_information_data.number_of_additional_network_logos == 0 steps[index + 1]
steps[index + 2]
else
steps[index + 1]
end
end end
end end
@@ -42,16 +52,29 @@ class EmployerSetupForm
steps[index - 1] if index && index > 0 steps[index - 1] if index && index > 0
end end
def save def permitted_params(params)
if valid? params.require(:employer_setup_data).permit(
pl_plan_key = attributes[:general_information_data][:pl_plan_key] :pl_plan_key,
EmployerSetupGeneralInformationForm.new(attributes[:general_information_data]).save :current_step
EmployerSetupPlansForm.new(attributes[:plans_data]).save(pl_plan_key) )
EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data]).save(pl_plan_key)
true
else
false
end
end end
def self.permitted_params
[
:pl_plan_key,
:current_step
]
end
# def save
# if valid?
# EmployerSetupGeneralInformationForm.new(attributes[:general_information_data]).save
# EmployerSetupPlansForm.new(attributes[:plans_data]).save
# EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data]).save
# true
# else
# false
# end
# end
end end
@@ -5,27 +5,48 @@ class EmployerSetupGeneralInformationForm
attribute :name, :string attribute :name, :string
attribute :employer_logo attribute :employer_logo
attribute :group_number, :string attribute :group_number, :string
attribute :dental, :boolean attribute :dental, :boolean, default: false
attribute :pl_plan_key, :string attribute :pl_plan_key, :string
attribute :effect_date, :string attribute :effect_date, :string
attribute :number_of_plans, :integer # attribute :number_of_plans, :integer
attribute :network, :string attribute :network, :string
attribute :number_of_additional_network_logos, :integer # attribute :number_of_additional_network_logos, :integer
validates :name, presence: true validates :name, presence: true
validates :employer_logo, presence: true validates :employer_logo, presence: true
validates :group_number, presence: true validates :group_number, presence: true
validates :pl_plan_key, presence: true validates :pl_plan_key, presence: true
validates :effect_date, presence: true validates :effect_date, presence: true
validates :number_of_plans, presence: true # validates :number_of_plans, presence: true
validates :network, presence: true validates :network, presence: true
# validates :number_of_additional_network_logos, presence: true if network = "cigna+" # validates :number_of_additional_network_logos, presence: true if network = "cigna+"
# def initialize(params = {}) # def initialize(attributes = {})
# super(params) # if attributes
# # Ensure the attribute is a hash after initialization # permitted_attributes = form_strong_params(attributes)
# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs] # super(permitted_attributes)
# end # end
def initialize(params = {})
if params.present?
params = permitted_params(params)
end
super(params)
end
def permitted_params(params)
params.require(:employer_setup_general_information_form).permit(
:name,
:employer_logo,
:group_number,
:dental,
:pl_plan_key,
:effect_date,
:number_of_plans,
:network,
:number_of_additional_network_logos
)
end
def save def save
# Implement logic to save data to models after all steps are complete # Implement logic to save data to models after all steps are complete
@@ -40,8 +61,8 @@ class EmployerSetupGeneralInformationForm
) )
# Replace fairos_info with template like for benefits # Replace fairos_info with template like for benefits
fairos_info = Vhcs::HLRXCrosRef.where(pl_plan_key: 52).first fairos_info = Vhcs::HlrxCrosRef.where(pl_plan_key: 52).first
hlrx_cros_ref = Vhcs::HLRXCrosRef.create!( hlrx_cros_ref = Vhcs::HlrxCrosRef.create!(
group_no: group_number, group_no: group_number,
rx_group_id: group_number, rx_group_id: group_number,
help_desk: fairos_info.help_desk, help_desk: fairos_info.help_desk,
@@ -51,15 +72,26 @@ class EmployerSetupGeneralInformationForm
) )
web_employer = BrittonWeb::Employers.create!( web_employer = BrittonWeb::Employers.create!(
name: name,
pl_plan_key: pl_plan_key, pl_plan_key: pl_plan_key,
dental_plan: dental, dental_plan: dental,
single_card_template: 'FairosRxIDCard', single_card_template: 'FairosRxIDCard',
logo: employer_logo.filename logo: employer_logo.original_filename
) )
default_network_logo =
case
when network.include?("cig")
"CignaLogo.png"
when network.include?("med")
"Logo_MC_PMS.png"
else
"CignaLogo.png"
end
BrittonWeb::NetworkLogos.create!( BrittonWeb::NetworkLogos.create!(
employer: web_employer, employer_id: web_employer.id,
net_logo: network, net_logo: default_network_logo,
default: true default: true
) )
@@ -4,29 +4,82 @@ class EmployerSetupNetworkExceptionsForm
Network_exception = Struct.new(:network_logo, :exceptions) Network_exception = Struct.new(:network_logo, :exceptions)
attribute :network_exceptions, :array_of_items, default: -> { [] } attribute :network_exceptions, :array_of_items, default: -> { [] }
attribute :pl_plan_key, :string
attribute :number_of_additional_network_logos, :integer
# validates :network_exceptions, presence: true if number_of_additional_network_logos > 0 # validates :network_exceptions, presence: true if number_of_additional_network_logos > 0
# def initialize(params = {}) def initialize(params = {})
# super(params) if params.present? && params[:employer_setup_network_exceptions_form].is_a?(ActionController::Parameters)
# # Ensure the attribute is a hash after initialization params = permitted_params(params)
# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs] end
# end super(params)
end
def save(pl_plan_key) def permitted_params(params)
params.require(:employer_setup_network_exceptions_form).permit(
network_exceptions: [
:network_logo,
exceptions: [
:type,
:value
]
]
)
end
# def self.permitted_params
# [
# network_exceptions: [
# :network_logo,
# exceptions: [
# :type,
# :value
# ]
# ]
# ]
# end
def pull_from_employer_setup_form(attributes = {})
if attributes['pl_plan_key']
self.pl_plan_key = attributes['pl_plan_key']
end
if attributes['number_of_additional_network_logos']
self.number_of_additional_network_logos = attributes['number_of_additional_network_logos']
end
end
def process_for_save(network_exceptions)
ne_array = []
network_exceptions.first.each do |ne|
processed_ne = ne.last
exceptions_array = []
processed_ne['exceptions'].each do |e|
exceptions_array.push(e.last)
end
processed_ne['exceptions'] = exceptions_array
ne_array.push(processed_ne)
end
ne_array
end
def save
# Implement logic to save data to models after all steps are complete # Implement logic to save data to models after all steps are complete
# For example, create a User record with the collected data # For example, create a User record with the collected data
if valid? if valid?
employer = BrittonWeb::Employers.find_by(pl_plan_key: pl_plan_key) employer = BrittonWeb::Employers.find_by(pl_plan_key: pl_plan_key)
network_exceptions.each do |ne| network_exceptions_data = process_for_save(network_exceptions)
BrittonWeb::NetworkLogos.create!( network_exceptions_data.each do |ne|
employer: employer, ne['exceptions'].each do |ex|
net_logo: ne.network_logo, BrittonWeb::NetworkLogos.create!(
exception_type: ne.type, employer_id: employer.id,
exception_value: ne.value, net_logo: ne['network_logo'].original_filename,
default: false exception_type: ex['type'].downcase,
) exception_value: ex['value'],
default: false
)
end
end end
true true
else else
+115 -16
View File
@@ -2,40 +2,111 @@ class EmployerSetupPlansForm
include ActiveModel::Model include ActiveModel::Model
include ActiveModel::Attributes include ActiveModel::Attributes
attribute :plans, array: true, default: -> { [] } PLAN_COLORS = ['atmosphere', 'copper', 'bluemana', 'bronze', 'cobalt', 'verdigris']
# attribute :benefit_descs, :hash, default: -> { {} }
attr_accessor :id_card_templates # attribute :plans, array: true, default: []
attr_accessor :id_card_template_benefits attribute :plans, array: true, default: -> { [new_plan] }
attr_accessor :benefit_descs attribute :pl_plan_key, :string
attribute :number_of_plans, :integer
attribute :benefit_descs, hash: true, default: -> { new_plan }
attr_accessor :plan_templates
attr_accessor :benefits_template
validates :plans, presence: true validates :plans, presence: true
# validates :benefit_descs, presence: true validates :benefit_descs, presence: true
def initialize(params = {}) def initialize(params = {})
if params.present?
params = permitted_params(params)
end
super(params) super(params)
@id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK") @plan_templates = IdCardBenefitsTemplate.where.not(title: "BLANK")
@id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence) @benefits_template = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence)
# if attributes.present? && attributes[:plans].present?
# self.plans = Array(attributes[:plans])
# else
# self.plans = [new_plan]
# end
end end
# def benefit_descs # def plans_attributes=(attributes)
# @benefit_descs ||= {} # self.plans = attributes.values.map { |plan_attrs| Plan.new(plan_attrs) }
# end # end
def save(pl_plan_key) def persisted?
false
end
# The core method to initialize the array with a single blank item.
def ensure_one_plan_exists
if plans.empty?
self.plans << PlanForm.new
self.plans << PlanForm.new
end
end
def bulild_descs_plan
self.benefit_descs = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence)
end
def self.new_plan
plan = {}
self.permited_plans_keys.each do |key|
plan[key] = ""
end
plan
end
def permitted_params(params)
params.require(:employer_setup_plans_form).permit(
:pl_plan_key,
plans: self.permited_plans_keys,
benefit_descs: self.permited_plans_keys
)
end
def pull_from_employer_setup_form(attributes = {})
if attributes['pl_plan_key']
self.pl_plan_key = attributes['pl_plan_key']
end
if attributes['number_of_plans']
self.number_of_plans = attributes['number_of_plans']
end
end
# def form_strong_params(attributes)
# attributes.require(:employer_setup_plans_form).permit(
# plans: permited_plans_keys,
# benefit_descs: benefit_sequence_keys
# )
# end
def self.permited_plans_keys
(1..14).map { |i| "benefit_#{i}".to_sym }.push(:plan_id)
end
def permited_plans_keys
(1..14).map { |i| "benefit_#{i}".to_sym }.push(:plan_id)
end
def save
# Implement logic to save data to models after all steps are complete # Implement logic to save data to models after all steps are complete
# For example, create a User record with the collected data # For example, create a User record with the collected data
if valid? if valid?
plans.each do |plan| plans.each do |plan|
plan_id = plan.delete(:plan_id) plan_info = plan.last
plan.each do |key, value| plan_id = plan_info.delete(:plan_id).to_i
Vhcs::HLEgglestonCardBenefit.create( plan_info.each do |key, value|
sequence = key.delete_prefix("benefit_").to_i
Vhcs::HlEgglestonCardBenefit.create(
plan_id: plan_id, plan_id: plan_id,
benefit_desc: benefit_descs["#{key}"], benefit_desc: benefit_descs["#{key}"],
benefit: value, benefit: value,
sequence: key, sequence: sequence,
plan_key: pl_plan_key plan_key: pl_plan_key
) )
end end
@@ -47,3 +118,31 @@ class EmployerSetupPlansForm
end end
end end
class PlanForm
include ActiveModel::Model
include ActiveModel::Attributes
attribute :plan_id, :string
def initialize(attributes = {})
self.generate_attributes(14, "benefit_")
super(attributes)
end
def persisted?
false
end
def generate_attributes(count, prefix)
count.times do |i|
# attr_accessor :"#{prefix}#{i + 1}"
self.class.attribute "#{prefix}#{i + 1}".to_sym, :string
end
end
end
# dynamic_attribute_names.each do |attr_name|
# # Define each attribute as a String type (you can customize the type)
# self.class.attribute attr_name.to_sym, :string
# end
+5 -1
View File
@@ -1,5 +1,9 @@
// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails // Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
import "@hotwired/turbo-rails" import "@hotwired/turbo-rails"
import "controllers"
import "trix" import "trix"
import "@rails/actiontext" import "@rails/actiontext"
import { Application } from "@hotwired/stimulus"
import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading"
const application = Application.start()
eagerLoadControllersFrom("controllers", application)
@@ -0,0 +1,32 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static values = {
formColor: { type: Array, default: [] } // Declares 'items' as an Array value
}
static targets = ["template", "container", "networkLogo", "button"]
add(event) {
event.preventDefault()
event.stopPropagation()
const content = this.#updateTemplateNetwork()
this.buttonTarget.insertAdjacentHTML('beforebegin', content);
// this.containerTarget.insertAdjacentHTML("beforeend", content)
}
#updateTemplateNetwork() {
const nextIndex = this.networkLogoTargets.length
const num_of_colors = this.formColorValue.length
let colorIndex = 0
if (nextIndex != 0) {
colorIndex = nextIndex % num_of_colors
}
const newColor = this.formColorValue[colorIndex]
return this.templateTarget.innerHTML
.replace(/NEW_RECORD/g, nextIndex)
.replace(/NEXT_COLOR/g, newColor)
}
}
@@ -0,0 +1,20 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static targets = ["template", "container"]
connect() {
console.log("connect")
}
add(event) {
console.log("start")
event.preventDefault()
event.stopPropagation()
const content = this.templateTarget.innerHTML.replace(/NEW_EXC_RECORD/g, new Date().getTime())
this.containerTarget.insertAdjacentHTML("beforeend", content)
console.log("end")
}
}
@@ -0,0 +1,34 @@
import { Controller } from "@hotwired/stimulus"
export default class extends Controller {
static values = {
formColor: { type: Array, default: [] } // Declares 'items' as an Array value
}
static targets = ["template", "container", "plan", "button"]
add(event) {
event.preventDefault()
event.stopPropagation()
const content = this.#updateTemplatePlan()
this.buttonTarget.insertAdjacentHTML("beforebegin", content)
}
#updateTemplatePlan() {
const nextIndex = this.planTargets.length
const num_of_colors = this.formColorValue.length
let colorIndex = 0
if (nextIndex != 0) {
colorIndex = nextIndex % num_of_colors
}
const newColor = this.formColorValue[colorIndex]
return this.templateTarget.innerHTML
.replace(/NEW_RECORD/g, nextIndex)
.replace(/NEW_PLAN/g, nextIndex + 1)
.replace(/NEXT_COLOR/g, newColor)
}
}
@@ -2,7 +2,10 @@ import { Controller } from "@hotwired/stimulus";
export default class extends Controller { export default class extends Controller {
static values = { url: String }; static values = { url: String };
static targets = ["benefit_1", "benefit_2", "benefit_3", "benefit_4", "benefit_5", "benefit_6", "benefit_7", "benefit_8", "benefit_9", "benefit_10", "benefit_11", "benefit_12", "benefit_13", "benefit_14"]; static targets = ["benefit"];
connect() {
}
async fetchData(event) { async fetchData(event) {
const templateId = event.target.value; const templateId = event.target.value;
@@ -11,25 +14,27 @@ export default class extends Controller {
return; return;
} }
const url = "/id_card_benefits_templates/get_templates_benefits/:id".replace(':id', templateId); const url = `/id_card_benefits_templates/get_template_benefits/${templateId}`
const response = await fetch(url); const response = await fetch(url);
const templateBenefitsData = await response.json(); const templateBenefitsData = await response.json();
this.#updateFields(templateBenefitsData)
this.nameTarget.value = templateData.name;
this.descriptionTarget.value = templateData.description;
} }
clearFields() { clearFields() {
this.nameTarget.value = '';
this.descriptionTarget.value = '';
} }
updateFields(templateBenefitsData) { async #updateFields(templateBenefitsData) {
templateBenefitsData.forEach(function(benefit) { const benefitTargetsList = this.benefitTargets
const propertyName = `benefit_${benefit.sequence}` templateBenefitsData.forEach(function(bene) {
this[propertyName].value = benefit.benefit const targetElement = benefitTargetsList.find(
(element) => element.dataset.sequence == bene.sequence
);
if (targetElement) {
targetElement.value = bene.benefit;
} else {
console.error(`Target not found for sequence: ${bene.sequence}`);
}
}); });
} }
} }
+21
View File
@@ -0,0 +1,21 @@
module BrittonWeb
class Employers < BrittonWebRecord
# self.table_name = 'employers'
alias_attribute :id, :id
alias_attribute :name, :name
alias_attribute :pl_plan_key, :pl_plan_key
alias_attribute :plan_id, :plan_id
alias_attribute :dental_plan, :dental_plan
alias_attribute :single_card_template, :single_card_template
alias_attribute :multiple_card_template, :multiple_card_template
alias_attribute :logo, :logo
alias_attribute :active, :active
alias_attribute :broker_id, :broker_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+17
View File
@@ -0,0 +1,17 @@
module BrittonWeb
class NetworkLogos < BrittonWebRecord
self.table_name = 'network_logos'
alias_attribute :id, :id
alias_attribute :net_logo, :net_logo
alias_attribute :exception_type, :exception_type
alias_attribute :exception_value, :exception_value
alias_attribute :default, :default
alias_attribute :employer_id, :employer_id
alias_attribute :created_at, :created_at
alias_attribute :updated_at, :updated_at
end
end
+4
View File
@@ -0,0 +1,4 @@
class BrittonWebRecord < ActiveRecord::Base
self.abstract_class = true
connects_to database: { writing: :britton_web, reading: :britton_web }
end
+3
View File
@@ -0,0 +1,3 @@
class EmployerSetupProcess < ApplicationRecord
has_many :plans
end
+17
View File
@@ -0,0 +1,17 @@
class Plan < ApplicationRecord
belongs_to :employer_setup_process
has_many :plan_benefits
after_create :create_default_benefits
private
def create_default_benefits
benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence)
benefits.each do |ben|
plan_benefits.create(benefit_desc: ben.benefit_desc, sequence: ben.sequence)
end
end
end
+3
View File
@@ -0,0 +1,3 @@
class PlanBenefit < ApplicationRecord
belongs_to :plan
end
+1 -1
View File
@@ -1,4 +1,4 @@
module VHCS module Vhcs
class HlPlanCode < VhcsRecord class HlPlanCode < VhcsRecord
self.table_name = 'HlPlanCode' self.table_name = 'HlPlanCode'
+1 -1
View File
@@ -1,5 +1,5 @@
module Vhcs module Vhcs
class HLRXCrosRef < VhcsRecord class HlrxCrosRef < VhcsRecord
self.table_name = 'HLRXCrosRef' self.table_name = 'HLRXCrosRef'
-1
View File
@@ -1,5 +1,4 @@
class VhcsRecord < ActiveRecord::Base class VhcsRecord < ActiveRecord::Base
self.abstract_class = true self.abstract_class = true
# establish_connection :vhcs
connects_to database: { writing: :vhcs, reading: :vhcs } connects_to database: { writing: :vhcs, reading: :vhcs }
end end
+156
View File
@@ -0,0 +1,156 @@
class BenefitsWordDocProcessor
def initialize(word_doc, process=nil)
@word_doc = word_doc
if process
@process = process
else
@process = EmployerSetupProcess.new
end
end
def call
doc = Docx::Document.open(@word_doc)
index = 40
general_information = doc.paragraphs.slice(0, index)
plan_information = doc.paragraphs.slice(index + 1..)
general_fields(general_information)
plans(plan_information)
logo
@process
end
private
def general_fields(general_information)
fields = ['Group Number:', 'Employer Name:', 'Group Effective Date:']
general_information.each do |gi|
field_string = gi.to_s
if field_string.include?('Group Number:')
value = field_string.delete_prefix('Group Number:').strip
@process.group_number = value
elsif field_string.include?('Employer Name:')
value = field_string.delete_prefix('Employer Name:').strip
@process.employer_name = value
elsif field_string.include?('Group Effective Date:')
value = field_string.delete_prefix('Group Effective Date:').strip
@process.effect_date = value
end
end
end
def logo
extracted_images = []
Zip::File.open(@word_doc) do |zip_file|
zip_file.each do |entry|
if entry.name.start_with?('word/media/') && !entry.directory?
filename = File.basename(entry.name)
image_data = entry.get_input_stream.read
extracted_images << { filename: filename, data: image_data }
end
end
end
if extracted_images.length > 1
@process.logo_filename = extracted_images.last[:filename]
end
end
def plans(plan_information)
plans_array = []
plan_information.each_with_index do |pin, i|
if pin.to_s.match?(/\d*\.?\d+k/i)
new_plan = {title: pin.to_s.strip, start_index: i, benefits: []}
plans_array.push(new_plan)
end
end
plans_array.each do |pl|
new_plan = Plan.create(title: pl[:title], employer_setup_process: @process)
plan_fields = plan_information.slice(pl[:start_index] + 1, 14)
plan_fields.each_with_index do |pf, i|
field_string = pf.to_s
if field_string.strip.length > 1
case field_string
when ->(string) { string.include?("Physician Visit") }
value = field_string.delete_prefix("Physician Visit")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "Primary Visit")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Specialist Visit") }
value = field_string.delete_prefix("Specialist Visit")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "Specialist Visit")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Urgent Care") }
value = field_string.delete_prefix("Urgent Care")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "Urgent Care")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Individual Deductible (in network )") }
value = field_string.delete_prefix("Individual Deductible (in network )")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "INNInd Ded")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Family Deductible(in network )") }
value = field_string.delete_prefix("Family Deductible(in network )")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "INNFamily Ded")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Individual Deductible (out of network)") }
value = field_string.delete_prefix("Individual Deductible (out of network)")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "OONInd Ded")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Family Deductible (out of network) ") }
value = field_string.delete_prefix("Family Deductible (out of network) ")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "OONFamily Ded")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Co-Insurance") }
value = field_string.delete_prefix("Co-Insurance")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "Co-Insurance")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Out-of-Pocket(in network) ") }
value = field_string.delete_prefix("Out-of-Pocket(in network) ")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "INNInd OOP")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Out-of-Pocket Family(in network) ") }
value = field_string.delete_prefix("Out-of-Pocket Family(in network) ")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "INNFamily OOP")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Out-of-Pocket(out of network) ") }
value = field_string.delete_prefix("Out-of-Pocket(out of network) ")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "OONInd OOP")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Out-of-Pocket Family (out of network) ") }
value = field_string.delete_prefix("Out-of-Pocket Family (out of network) ")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "OONFamily OOP")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Emergency Room ") }
value = field_string.delete_prefix("Emergency Room ")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "Emergency Room")
new_benefit.benefit = value
new_benefit.save
when ->(string) { string.include?("Preventive Care") }
value = field_string.delete_prefix("Preventive Care")
new_benefit = new_plan.plan_benefits.find_by(benefit_desc: "Preventive Care")
new_benefit.benefit = value
new_benefit.save
end
end
end
end
end
end
+2 -6
View File
@@ -6,11 +6,7 @@ class ArrayOfItemsType < ActiveModel::Type::Value
Array.wrap(value).map do |item_data| Array.wrap(value).map do |item_data|
# Assuming item_data is a hash, this creates an instance of the Item class. # Assuming item_data is a hash, this creates an instance of the Item class.
# You can modify this part to match your object's initializer. # You can modify this part to match your object's initializer.
if item_data.is_a?(Hash) item_data # Return the item as-is if it's already an object
Item.new(item_data)
else
item_data # Return the item as-is if it's already an object
end
end end
end end
@@ -20,4 +16,4 @@ class ArrayOfItemsType < ActiveModel::Type::Value
end end
end end
ActiveModel::Type.register(:array_of_items, ArrayOfItemsType) # ActiveModel::Type.register(:array_of_items, ArrayOfItemsType)
@@ -10,9 +10,6 @@
<div class="w-1/5"> <div class="w-1/5">
<%= f.text_field :group_number, label: { text: "Group/Medical Number" }, class: "w-full" %> <%= f.text_field :group_number, label: { text: "Group/Medical Number" }, class: "w-full" %>
</div> </div>
<div>
<%= f.check_box :dental %>
</div>
</div> </div>
<div class="flex space-x-10"> <div class="flex space-x-10">
<div class="w-1/5"> <div class="w-1/5">
@@ -23,15 +20,9 @@
</div> </div>
</div> </div>
<div class="flex space-x-10"> <div class="flex space-x-10">
<div class="w-1/5">
<%= f.select :number_of_plans, options_for_select((1..6).to_a), label: { text: "Number of Plans" }, class: "w-1/3" %>
</div>
<div class="w-1/5"> <div class="w-1/5">
<%= f.select :network, options_for_select([["Cigna", "cig"], ["Cigna+Regional", "cig+"], ["Medcost", "med"]]), label: { text: "Provider Network" }, data: { controller: "form-toggle", action: "change->form-toggle#toggleDivs" }, class: "w-full" %> <%= f.select :network, options_for_select([["Cigna", "cig"], ["Cigna+Regional", "cig+"], ["Medcost", "med"]]), label: { text: "Provider Network" }, data: { controller: "form-toggle", action: "change->form-toggle#toggleDivs" }, class: "w-full" %>
</div> </div>
<div id="div-a" class="w-1/5" data-form-toggle-target="divA">
<%= f.select :number_of_additional_network_logos, options_for_select((0..6).to_a), label: { text: "Number of Additional Network Logos" }, class: "w-1/3" %>
</div>
</div> </div>
<div class="flex space-x-5 items-center mt-4"> <div class="flex space-x-5 items-center mt-4">
<label for="file_upload_input" class="cursor-pointer bg-atmosphere hover:bg-bluetang text-platinum font-bold py-2 px-4 rounded border border-platinum"> <label for="file_upload_input" class="cursor-pointer bg-atmosphere hover:bg-bluetang text-platinum font-bold py-2 px-4 rounded border border-platinum">
@@ -0,0 +1,64 @@
<div class="min-h-screen w-full flex flex-col" data-controller="add-alt-network-logo" data-add-alt-network-logo-form-color-value="<%= EmployerSetupPlansForm::PLAN_COLORS.to_json %>">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">Provider Network</h3>
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<div class="flex w-full justify-start">
<div class="flex flex-wrap w-full" data-add-alt-network-logo-target="container">
<%= button_tag "Add a Regional Logo", class: "cursor-pointer text-lg font-medium py-2 px-4 rounded w-1/7 h-75 my-8 text-[#E0E0E0] rounded-lg border border-[#C2C2C2] hover:shadow-[0_0_10px_3px_#93c5fd]", data: { action: "add-alt-network-logo#add", add_alt_network_logo_target: "button" } %>
</div>
</div>
<div class="py-10">
<%= f.submit "Continue to Summary" %>
</div>
<template data-add-alt-network-logo-target="template">
<%= f.fields_for :network_exceptions, index: 'NEW_RECORD' do |network_fields| %>
<div class="flex flex-col my-8 mr-3 space-y-6 px-3" data-controller="add-network-exception">
<div class="flex space-x-5 items-center mt-4">
<label for="file_upload_input_NEW_RECORD" class="cursor-pointer bg-NEXT_COLOR hover:bg-NEXT_COLOR-tinted text-platinum font-bold py-2 px-4 rounded border border-platinum">
Choose Network Logo File
</label>
<span id="file_name_display_NEW_RECORD" class="ml-2 text-NEXT_COLOR font-semibold">No file chosen</span>
<%= network_fields.file_field :network_logo, class: "hidden", id: "file_upload_input_NEW_RECORD", data: { add_alt_network_logo_target: "networkLogo" } %>
</div>
<%= network_fields.fields_for :exceptions, index: 0 do |exception_fields| %>
<div class="flex space-x-6 w-full">
<div class="w-full">
<%= exception_fields.select :type, options_for_select(["Zip","State"]), label: { text: "Exception Type" }, prompt: "Select Type", class: "w-full" %>
</div>
<div class="w-full">
<%= exception_fields.text_field :value, label: { text: "Exception Value" }, class: "w-full" %>
</div>
</div>
<% end %>
<div class="flex flex-col w-full space-y-6" data-add-network-exception-target="container"></div>
<%= button_tag "Add an exception rule", class: "cursor-pointer bg-NEXT_COLOR hover:bg-NEXT_COLOR-tinted text-platinum text-lg font-bold py-2 px-4 rounded border border-platinum w-full", data: { action: "add-network-exception#add" } %>
<template data-add-network-exception-target="template">
<%= network_fields.fields_for :exceptions, index: 'NEW_EXC_RECORD' do |exception_fields| %>
<div class="flex space-x-6 w-full">
<div class="w-full">
<%= exception_fields.select :type, options_for_select(["Zip","State"]), label: { text: "Exception Type" }, prompt: "Select Type", class: "w-full" %>
</div>
<div class="w-full">
<%= exception_fields.text_field :value, label: { text: "Exception Value" }, class: "w-full" %>
</div>
</div>
<% end %>
</template>
</div>
<% end %>
</template>
<% end %>
</div>
<script>
const logoButtons = document.querySelectorAll('[id^="file_upload_input_"]');
logoButtons.forEach(button => {
button.addEventListener('change', function(e) {
var fileName = e.target.files[0] ? e.target.files[0].name : 'No file chosen';
var targetIndex = e.target.id.slice(-1);
document.getElementById(`file_name_display_${targetIndex}`).textContent = fileName;
});
})
</script>
@@ -1,41 +0,0 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">Provider Network</h3>
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<% @form.number_of_additional_network_logos.to_i.times do |i| %>
<%= f.fields_for :network_exceptions do |network_fields| %>
<div class="w-full flex flex-col my-8 space-y-6">
<div class="flex space-x-5 items-center mt-4">
<label for="file_upload_input" class="cursor-pointer bg-atmosphere hover:bg-bluetang text-platinum font-bold py-2 px-4 rounded border border-platinum">
Choose Network Logo File
</label>
<span id="file_name_display" class="ml-2 text-bluemana font-semibold">No file chosen</span>
<%= network_fields.file_field :network_logo, class: "hidden", id: "file_upload_input" %>
</div>
<% 2.to_i.times do |j| %>
<%= network_fields.fields_for :exceptions do |exception_fields| %>
<div class="flex space-x-10">
<div class="w-1/5">
<%= exception_fields.select :type, options_for_select(["Zipcode","State"]), label: { text: "Exception Type" }, prompt: "Select Type", class: "w-full" %>
</div>
<div class="w-1/5">
<%= exception_fields.text_field :value, label: { text: "Exception Value" }, class: "w-full" %>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
<% end %>
<div class="py-10">
<%= f.submit "Continue to Summary" %>
</div>
<% end %>
</div>
<script>
document.getElementById('file_upload_input').addEventListener('change', function(e) {
var fileName = e.target.files[0] ? e.target.files[0].name : 'No file chosen';
document.getElementById('file_name_display').textContent = fileName;
});
</script>
@@ -1,38 +0,0 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<%= form_with url: 'create_plans', method: :post do |form| %>
<div class="w-full flex">
<div class="flex flex-col mr-4">
<% @id_card_template_benefits.each do |bene| %>
<div>
<%= form.text_field "plans[benefit_descs][#{bene.sequence}]", label: { text: "Benefit Description" }, value: "#{bene.benefit_desc}" %>
</div>
<% end %>
</div>
<% @employer_data['employer']['number_of_plans'].to_i.times do |i| %>
<div class="flex flex-col">
<div>
<%= form.text_field "plans[plan_#{i}][plan_id]", label: { text: "Plan Id" } %>
</div>
<div class="bg-gray-200 rounded py-2 px-4 text-bluetang font-semibold leading-tight">
<select data-action="benefits-template-picker#fetchData" data-benefits-template-picker-url-value="/id_card_benefits_templates/get_templates_benefits/:id">
<option value="">Select Existing Template (optional)</option>
<% @id_card_templates.each do |temp| %>
<option value="<%= temp.id %>"><%= temp.name %></option>
<% end %>
</select>
</div>
<% @id_card_template_benefits.each do |bene| %>
<div>
<div>
<%= form.text_field "plans[plan_#{i}][#{bene.sequence}]", label: { text: "Benefit Value" }, data: { benefits_template_picker_target: "benefit_#{bene.sequence}" } %>
</div>
</div>
<% end %>
</div>
<% end %>
</div>
<%= form.submit "Summary" %>
</div>
<% end %>
</div>
+56 -30
View File
@@ -1,43 +1,69 @@
<div class="bg-deepcove min-h-screen w-full flex flex-col"> <div class="min-h-screen w-full flex flex-col" data-controller="add-plan" data-add-plan-form-color-value="<%= EmployerSetupPlansForm::PLAN_COLORS.to_json %>">
<h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1> <h1 class="font-bold text-4xl text-platinum">New Employer Setup</h1>
<h3 class="font-bold text-2xl text-bluemana">Medical Plans</h3> <h3 class="font-bold text-2xl text-bluemana">Medical Plans</h3>
<div class="flex flex-col pl-6"> <div class="flex flex-col pl-6">
<%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %> <%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %>
<%= f.text_field :pl_plan_key, label: { text: "Employer PL Plan Key" }, class: "justify-self-start" %>
<div class="w-full flex my-8"> <div class="w-full flex my-8">
<div class="flex flex-col justify-end pr-6"> <div class="flex flex-wrap w-full" data-add-plan-target="container">
<% @id_card_template_benefits.each do |bene| %> <div class="flex flex-col items-stretch justify-end pr-6 pl-1 w-1/4">
<%= f.fields_for :benefit_descs do |bd_fields| %> <%= f.fields_for :benefit_descs do |plan_benefit_fields| %>
<%= plan_benefit_fields.text_field :plan_id, class: "hidden", value: "descriptions" %>
<% @form.benefits_template.each do |bene| %>
<div> <div>
<%= bd_fields.text_field "#{bene.sequence}", label: { text: "Benefit Description #{bene.sequence}" }, value: "#{bene.benefit_desc}" %> <%= plan_benefit_fields.text_field "benefit_#{bene.sequence}", label: { text: "Benefit Description #{bene.sequence}" }, value: "#{bene.benefit_desc}", class: "w-full" %>
</div> </div>
<% end %> <% end %>
<% end %> <% end %>
</div>
<% @form.number_of_plans.to_i.times do |i| %>
<% border_colors = ['border-atmosphere', 'border-copper', 'border-bluemana'] %>
<% text_colors = ['text-atmosphere', 'text-copper', 'text-bluemana'] %>
<div class="inline-flex flex-col justify-end pr-6 pl-1 relative">
<div class="absolute left-0 top-[2%] h-[98%] border-l-4 <%= border_colors[i] %> rounded-bl-lg"></div>
<div class="font-bold text-2xl <%= text_colors[i] %> -ml-[6px] z-2 w-full">
<%= "Plan #{i + 1}" %>
</div>
<%= f.fields_for :plans do |plan_fields| %>
<div class="pl-1 w-full">
<%= plan_fields.text_field :plan_id, label: { text: "Plan Id" }, class: "w-full" %>
</div>
<div class="pl-1" data-controller="benefits_template_picker_controller">
<%= f.select :template_id, options_from_collection_for_select(@id_card_templates, :id, :name), { prompt: "Select Existing Template (optional)", data: { action: "benefits-template-picker#fetchData" }} %>
</div>
<% @id_card_template_benefits.each do |bene| %>
<div>
<div class="pl-1 w-full">
<%= plan_fields.text_field "#{bene.sequence}", label: { text: "Benefit Value #{bene.sequence}" }, data: { benefits_template_picker_target: "benefit_#{bene.sequence}" }, class: "w-full" %>
</div>
</div>
<% end %>
<% end %>
</div> </div>
<% end %> <% @form.plans.each_with_index do |plan, i| %>
<div class="inline-flex flex-col justify-end pr-6 pl-1 mt-10 relative w-1/4" data-controller="benefits-template-picker">
<div class="absolute left-0 top-[2%] h-[98%] border-l-4 <%= "border-#{EmployerSetupPlansForm::PLAN_COLORS[i]}" %> rounded-bl-lg"></div>
<div class="font-bold text-2xl <%= "text-#{EmployerSetupPlansForm::PLAN_COLORS[i]}" %> -ml-[6px] z-2 w-full">
<%= "Plan #{i + 1}" %>
</div>
<%= f.fields_for :plans, index: i do |plan_fields| %>
<div class="pl-1 w-full">
<%= plan_fields.text_field :plan_id, label: { text: "Plan Id" }, class: "w-full", data: { add_plan_target: "plan" } %>
</div>
<div class="pl-1">
<%= f.select :template_id, options_from_collection_for_select(@form.plan_templates, :id, :title), { prompt: "Select Plan Template" }, { data: { action: "benefits-template-picker#fetchData" }} %>
</div>
<% @form.benefits_template.each do |bene| %>
<div>
<div class="pl-1 w-full">
<%= plan_fields.text_field "benefit_#{bene.sequence}", label: { text: "Benefit Value #{bene.sequence}" }, data: { benefits_template_picker_target: "benefit", sequence: "#{bene.sequence}"}, class: "w-full" %>
</div>
</div>
<% end %>
<% end %>
</div>
<% end %>
<%= button_tag "Add a Plan", class: "cursor-pointer text-2xl font-bold py-2 pr-6 mt-10 w-[calc(24%-1rem)] w-1/4 min-h-[940px] text-[#E0E0E0] rounded-lg font-medium border border-[#E0E0E0] bg-[#173057] hover:bg-transparent hover:shadow-[0_0_10px_3px_#93c5fd] transition-colors duration-150", data: { action: "add-plan#add", add_plan_target: "button" } %>
<template data-add-plan-target="template">
<div class="inline-flex flex-col justify-end pr-6 pl-1 mt-10 relative w-1/4" data-controller="benefits-template-picker">
<div class="absolute left-0 top-[2%] h-[98%] border-l-4 border-NEXT_COLOR rounded-bl-lg"></div>
<div class="font-bold text-2xl text-NEXT_COLOR -ml-[6px] z-2 w-full">
<%= "Plan NEW_PLAN" %>
</div>
<%= f.fields_for :plans, index: 'NEW_RECORD' do |plan_fields| %>
<div class="pl-1 w-full">
<%= plan_fields.text_field :plan_id, label: { text: "Plan Id" }, class: "w-full", data: { add_plan_target: "plan" } %>
</div>
<div class="pl-1">
<%= f.select :template_id, options_from_collection_for_select(@form.plan_templates, :id, :title), { prompt: "Select Plan Template" }, { data: { action: "benefits-template-picker#fetchData" }} %>
</div>
<% @form.benefits_template.each do |bene| %>
<div>
<div class="pl-1 w-full">
<%= plan_fields.text_field "benefit_#{bene.sequence}", label: { text: "Benefit Value #{bene.sequence}" }, data: { benefits_template_picker_target: "benefit", sequence: "#{bene.sequence}"}, class: "w-full" %>
</div>
</div>
<% end %>
<% end %>
</div>
</template>
</div>
</div> </div>
<div class="py-10"> <div class="py-10">
<%= f.submit "Continue to Provider Network" %> <%= f.submit "Continue to Provider Network" %>
+10 -4
View File
@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<title>Railsondocker</title> <title>Baclight</title>
<meta name="viewport" content="width=device-width,initial-scale=1"> <meta name="viewport" content="width=device-width,initial-scale=1">
<%= csrf_meta_tags %> <%= csrf_meta_tags %>
<%= csp_meta_tag %> <%= csp_meta_tag %>
@@ -11,9 +11,15 @@
<%= javascript_importmap_tags %> <%= javascript_importmap_tags %>
</head> </head>
<body class="w-full flex bg-deepcove"> <body>
<main class="w-11/12 mt-28 px-5 flex"> <main>
<%= yield %> <div class="w-full h-screen flex bg-black justify-center items-center">
<div class="h-[98%] w-[calc(100%-1rem)] mt-1 mb-2 flex justify-center items-center shadow-[0_0_10px_3px_#93c5fd] rounded-xl bg-[#04153E]">
<div class="w-11/12 mt-8 px-5 flex">
<%= yield %>
</div>
</div>
</div>
</main> </main>
</body> </body>
</html> </html>
+13 -16
View File
@@ -1,17 +1,14 @@
<h1>Welcome</h1> <div class="flex items-center justify-center h-full w-full">
<div class="flex flex-col text-7xl font-bold text-[#2A4B6F] space-y-30">
<%= link_to "Articles", articles_path %> <div>
<span class="[text-shadow:0_0_20px_#fff,0_0_50px_#0090D9,0_0_80px_#0ff] text-[#04153E]">B</span>acl<span class="text-[#CD7F32]">i</span>ght
</div>
<h2>Stimulus Check</h2> <div>
<span class="[text-shadow:0_0_20px_#fff,0_0_50px_#0090D9,0_0_80px_#0ff] text-[#04153E]">B</span>acl<span class="relative inline-block">i<span class="absolute top-0 right-0 h-3 w-3 rounded-full bg-[#CD7F32] translate-y-[7px] -translate-x-[3px]"></span></span>ght
<div data-controller="hello"> </div>
<input data-hello-target="name" type="text"> <div>
<span class="justify-self-end [text-shadow:0_0_20px_#fff,0_0_50px_#0090D9,0_0_80px_#0ff] text-[#04153E]">B</span>acl<span class="relative inline-block">i<span class="absolute top-0 right-0 h-3 w-3 rounded-full bg-[#CD7F32] translate-y-[7px] -translate-x-[3px] shadow-[0_0_7px_2px_#93c5fd]"></span></span>ght
<button data-action="click->hello#greet"> </div>
Greet </div>
</button>
<span data-hello-target="output">
</span>
</div> </div>
+1 -1
View File
@@ -2,7 +2,7 @@
require "fileutils" require "fileutils"
APP_ROOT = File.expand_path("..", __dir__) APP_ROOT = File.expand_path("..", __dir__)
APP_NAME = "railsondocker" APP_NAME = "baclight"
def system!(*args) def system!(*args)
system(*args, exception: true) system(*args, exception: true)
+1 -1
View File
@@ -8,4 +8,4 @@ test:
production: production:
adapter: redis adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %> url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
channel_prefix: railsondocker_production channel_prefix: baclight_production
+9
View File
@@ -37,6 +37,15 @@ development:
password: BSTIBOY password: BSTIBOY
database_tasks: false database_tasks: false
tds_version: 7.3 tds_version: 7.3
britton_web:
<<: *default
host: 10.41.82.73
port: 1433
database: BrittonWeb
username: SA
password: Adm1nBb5
database_tasks: false
tds_version: 7.3
# The specified database role being used to connect to PostgreSQL. # The specified database role being used to connect to PostgreSQL.
# To create additional roles in PostgreSQL see `$ createuser --help`. # To create additional roles in PostgreSQL see `$ createuser --help`.
@@ -0,0 +1,3 @@
Rails.application.config.to_prepare do
ActiveModel::Type.register(:array_of_items, ArrayOfItemsType)
end
+1 -1
View File
@@ -2,7 +2,7 @@
Rails.application.routes.draw do Rails.application.routes.draw do
resources :employer_setup, only: [:new, :create] resources :employer_setup, only: [:new, :create]
get "welcome/index" get 'id_card_benefits_templates/get_template_benefits/:id', to: 'id_card_benefits_templates#get_template_benefits'
# Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500.
# Can be used by load balancers and uptime monitors to verify that the app is live. # Can be used by load balancers and uptime monitors to verify that the app is live.
@@ -0,0 +1,16 @@
class CreateEmployerSetupProcesses < ActiveRecord::Migration[7.2]
def change
create_table :employer_setup_processes do |t|
t.string :employer_name
t.string :group_number
t.string :effect_date
t.string :logo_filename
t.string :form_method
t.string :status
t.string :current_step
t.timestamps
end
end
end
+11
View File
@@ -0,0 +1,11 @@
class CreatePlans < ActiveRecord::Migration[7.2]
def change
create_table :plans do |t|
t.string :title
t.references :employer_setup_process, null: false, foreign_key: true
t.timestamps
end
end
end
@@ -0,0 +1,12 @@
class CreatePlanBenefits < ActiveRecord::Migration[7.2]
def change
create_table :plan_benefits do |t|
t.string :benefit_desc
t.string :benefit
t.integer :sequence
t.references :plan, null: false, foreign_key: true
t.timestamps
end
end
end
+33 -1
View File
@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.2].define(version: 2025_11_04_171752) do ActiveRecord::Schema[7.2].define(version: 2025_12_02_142512) do
create_table "action_text_rich_texts", force: :cascade do |t| create_table "action_text_rich_texts", force: :cascade do |t|
t.string "name", null: false t.string "name", null: false
t.text "body" t.text "body"
@@ -49,6 +49,18 @@ ActiveRecord::Schema[7.2].define(version: 2025_11_04_171752) do
t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
end end
create_table "employer_setup_processes", force: :cascade do |t|
t.string "employer_name"
t.string "group_number"
t.string "effect_date"
t.string "logo_filename"
t.string "form_method"
t.string "status"
t.string "current_step"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "id_card_benefits", force: :cascade do |t| create_table "id_card_benefits", force: :cascade do |t|
t.string "benefit_desc" t.string "benefit_desc"
t.string "benefit" t.string "benefit"
@@ -65,7 +77,27 @@ ActiveRecord::Schema[7.2].define(version: 2025_11_04_171752) do
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
create_table "plan_benefits", force: :cascade do |t|
t.string "benefit_desc"
t.string "benefit"
t.integer "sequence"
t.bigint "plan_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["plan_id"], name: "index_plan_benefits_on_plan_id"
end
create_table "plans", force: :cascade do |t|
t.string "title"
t.bigint "employer_setup_process_id", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["employer_setup_process_id"], name: "index_plans_on_employer_setup_process_id"
end
add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id" add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
add_foreign_key "id_card_benefits", "id_card_benefits_templates" add_foreign_key "id_card_benefits", "id_card_benefits_templates"
add_foreign_key "plan_benefits", "plans"
add_foreign_key "plans", "employer_setup_processes"
end end
+2 -1
View File
@@ -16,7 +16,8 @@ RUN --mount=type=cache,target=/var/cache/apt \
tdsodbc \ tdsodbc \
freetds-dev \ freetds-dev \
libvips \ libvips \
libpq-dev libpq-dev \
libyaml-dev
ENV LANG=C.UTF-8 \ ENV LANG=C.UTF-8 \
BUNDLE_JOBS=4 \ BUNDLE_JOBS=4 \
@@ -9,6 +9,10 @@ class LegacyDbModelGenerator < Rails::Generators::Base
@db_record = 'VhcsRecord'.constantize @db_record = 'VhcsRecord'.constantize
@module = 'Vhcs'.constantize @module = 'Vhcs'.constantize
@file_folder = 'vhcs' @file_folder = 'vhcs'
elsif db_name == 'BrittonWeb'
@db_record = 'BrittonWebRecord'.constantize
@module = 'BrittonWeb'.constantize
@file_folder = 'britton_web'
elsif db_name == 'HEBWeb' elsif db_name == 'HEBWeb'
@db_record = 'WebRecord'.constantize @db_record = 'WebRecord'.constantize
@module = 'HebWeb'.constantize @module = 'HebWeb'.constantize