diff --git a/.gitignore b/.gitignore index ac36ab6..8e1c9f8 100644 --- a/.gitignore +++ b/.gitignore @@ -72,3 +72,6 @@ yarn-debug.log* /config/master.key .DS_Store + +/app/assets/builds/* +!/app/assets/builds/.keep diff --git a/Dockerfile.db b/Dockerfile.db new file mode 100644 index 0000000..750d682 --- /dev/null +++ b/Dockerfile.db @@ -0,0 +1,9 @@ +FROM mcr.microsoft.com/mssql/server:2017-latest +ENV ACCEPT_EULA=Y +ENV MSSQL_SA_PASSWORD=Br1tt0nPassw0rd +ENV MSSQL_PID=Developer + +COPY init.sql . +COPY ./bin/dbentrypoint.sh . +EXPOSE 1434 +CMD /bin/bash dbentrypoint.sh \ No newline at end of file diff --git a/Gemfile b/Gemfile index 8149b56..55936a9 100644 --- a/Gemfile +++ b/Gemfile @@ -12,9 +12,6 @@ gem "rails", "~> 7.2" # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] gem "sprockets-rails" -# Use postgresql as the database for Active Record -gem "pg", "~> 1.5" - # Use the Puma web server [https://github.com/puma/puma] gem "puma", "~> 6.5" @@ -31,7 +28,7 @@ gem "stimulus-rails" gem "jbuilder" # Use Redis adapter to run Action Cable in production -gem "redis", "~> 5.3" +# gem "redis", "~> 5.3" # Use Kredis to get higher-level data types in Redis [https://github.com/rails/kredis] # gem "kredis" @@ -40,17 +37,17 @@ gem "redis", "~> 5.3" # gem "bcrypt", "~> 3.1.7" # Windows does not include zoneinfo files, so bundle the tzinfo-data gem -gem "tzinfo-data", platforms: %i[ windows jruby ] +gem "tzinfo-data", platforms: %i[ mingw mswin x64_mingw jruby ] # Reduces boot times through caching; required in config/boot.rb gem "bootsnap", require: false # Use Active Storage variants [https://guides.rubyonrails.org/active_storage_overview.html#transforming-images] -gem "image_processing", "~> 1.2" +# gem "image_processing", "~> 1.2" group :development, :test do # See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem - gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" + # gem "debug", platforms: %i[ mri windows ], require: "debug/prelude" # Static analysis for security vulnerabilities [https://brakemanscanner.org/] gem "brakeman", require: false @@ -70,6 +67,8 @@ group :development do # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] gem "rack-mini-profiler" + + gem "pry-rails" end group :test do @@ -77,3 +76,9 @@ group :test do gem "capybara" gem "selenium-webdriver" end + +gem 'activerecord-sqlserver-adapter' +gem 'tiny_tds' +gem 'devise' +gem 'pundit' +gem "tailwindcss-rails" \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock index 4c3c1b5..96aabc9 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -56,6 +56,9 @@ GEM activemodel (= 7.2.3) activesupport (= 7.2.3) timeout (>= 0.4.0) + activerecord-sqlserver-adapter (7.2.8) + activerecord (~> 7.2.0) + tiny_tds activestorage (7.2.3) actionpack (= 7.2.3) activejob (= 7.2.3) @@ -78,6 +81,7 @@ GEM public_suffix (>= 2.0.2, < 7.0) ast (2.4.3) base64 (0.3.0) + bcrypt (3.1.20) benchmark (0.5.0) bigdecimal (3.3.1) bindex (0.8.1) @@ -99,32 +103,25 @@ GEM regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) cgi (0.5.0) + coderay (1.1.3) concurrent-ruby (1.3.5) connection_pool (2.5.4) crass (1.0.6) date (3.5.0) - debug (1.11.0) - irb (~> 1.10) - reline (>= 0.3.8) + devise (4.9.4) + bcrypt (~> 3.0) + orm_adapter (~> 0.1) + railties (>= 4.1.0) + responders + warden (~> 1.2.3) diff-lcs (1.6.2) drb (2.2.3) erb (5.1.3) erubi (1.13.1) - ffi (1.17.2-aarch64-linux-gnu) - ffi (1.17.2-aarch64-linux-musl) - ffi (1.17.2-arm-linux-gnu) - ffi (1.17.2-arm-linux-musl) - ffi (1.17.2-arm64-darwin) - ffi (1.17.2-x86_64-darwin) - ffi (1.17.2-x86_64-linux-gnu) - ffi (1.17.2-x86_64-linux-musl) globalid (1.3.0) activesupport (>= 6.1) i18n (1.14.7) concurrent-ruby (~> 1.0) - image_processing (1.14.0) - mini_magick (>= 4.9.5, < 6) - ruby-vips (>= 2.0.17, < 3) importmap-rails (2.2.2) actionpack (>= 6.0.0) activesupport (>= 6.0.0) @@ -152,8 +149,7 @@ GEM net-smtp marcel (1.1.0) matrix (0.4.3) - mini_magick (5.3.1) - logger + method_source (1.1.0) mini_mime (1.1.5) minitest (5.26.0) msgpack (1.8.0) @@ -183,27 +179,28 @@ GEM racc (~> 1.4) nokogiri (1.18.10-x86_64-linux-musl) racc (~> 1.4) + orm_adapter (0.5.0) parallel (1.27.0) parser (3.3.10.0) ast (~> 2.4.1) racc - pg (1.6.2) - pg (1.6.2-aarch64-linux) - pg (1.6.2-aarch64-linux-musl) - pg (1.6.2-arm64-darwin) - pg (1.6.2-x86_64-darwin) - pg (1.6.2-x86_64-linux) - pg (1.6.2-x86_64-linux-musl) pp (0.6.3) prettyprint prettyprint (0.2.0) prism (1.6.0) + pry (0.15.2) + coderay (~> 1.1) + method_source (~> 1.0) + pry-rails (0.3.11) + pry (>= 0.13.0) psych (5.2.6) date stringio public_suffix (6.0.2) puma (6.6.1) nio4r (~> 2.0) + pundit (2.5.2) + activesupport (>= 3.0.0) racc (1.8.1) rack (3.2.4) rack-mini-profiler (4.0.1) @@ -252,13 +249,12 @@ GEM erb psych (>= 4.0.0) tsort - redis (5.4.1) - redis-client (>= 0.22.0) - redis-client (0.26.1) - connection_pool regexp_parser (2.11.3) reline (0.6.2) io-console (~> 0.5) + responders (3.2.0) + actionpack (>= 7.0) + railties (>= 7.0) rexml (3.4.4) rspec-core (3.13.6) rspec-support (~> 3.13.0) @@ -309,9 +305,6 @@ GEM lint_roller (~> 1.1) rubocop (~> 1.72, >= 1.72.1) ruby-progressbar (1.13.0) - ruby-vips (2.2.5) - ffi (~> 1.12) - logger rubyzip (3.2.2) securerandom (0.4.1) selenium-webdriver (4.38.0) @@ -331,8 +324,28 @@ GEM stimulus-rails (1.3.4) railties (>= 6.0.0) stringio (3.1.7) + tailwindcss-rails (4.4.0) + railties (>= 7.0.0) + tailwindcss-ruby (~> 4.0) + tailwindcss-ruby (4.1.16) + tailwindcss-ruby (4.1.16-aarch64-linux-gnu) + tailwindcss-ruby (4.1.16-aarch64-linux-musl) + tailwindcss-ruby (4.1.16-arm64-darwin) + tailwindcss-ruby (4.1.16-x86_64-darwin) + tailwindcss-ruby (4.1.16-x86_64-linux-gnu) + tailwindcss-ruby (4.1.16-x86_64-linux-musl) thor (1.4.0) timeout (0.4.4) + tiny_tds (3.3.0) + bigdecimal (~> 3) + tiny_tds (3.3.0-aarch64-linux-gnu) + bigdecimal (~> 3) + tiny_tds (3.3.0-aarch64-linux-musl) + bigdecimal (~> 3) + tiny_tds (3.3.0-x86_64-linux-gnu) + bigdecimal (~> 3) + tiny_tds (3.3.0-x86_64-linux-musl) + bigdecimal (~> 3) tsort (0.2.0) turbo-rails (2.0.20) actionpack (>= 7.1.0) @@ -343,6 +356,8 @@ GEM unicode-emoji (~> 4.1) unicode-emoji (4.1.0) useragent (0.16.11) + warden (1.2.9) + rack (>= 2.0.9) web-console (4.2.1) actionview (>= 6.0.0) activemodel (>= 6.0.0) @@ -368,19 +383,19 @@ PLATFORMS x86_64-linux-musl DEPENDENCIES + activerecord-sqlserver-adapter bootsnap brakeman bundler-audit capybara - debug - image_processing (~> 1.2) + devise importmap-rails jbuilder - pg (~> 1.5) + pry-rails puma (~> 6.5) + pundit rack-mini-profiler rails (~> 7.2) - redis (~> 5.3) rspec-rails rubocop-rails rubocop-rails-omakase @@ -388,6 +403,8 @@ DEPENDENCIES selenium-webdriver sprockets-rails stimulus-rails + tailwindcss-rails + tiny_tds turbo-rails tzinfo-data web-console diff --git a/Procfile.dev b/Procfile.dev index 852e6c7..94daa16 100644 --- a/Procfile.dev +++ b/Procfile.dev @@ -1,2 +1,2 @@ -web: bin/rails server -p 3000 -css: bin/rails dartsass:watch +web: bin/rails server -b 0.0.0.0 -p 3002 +css: bin/rails tailwindcss:watch[verbose] diff --git a/app/assets/builds/.keep b/app/assets/builds/.keep new file mode 100644 index 0000000..e69de29 diff --git a/app/assets/config/manifest.js b/app/assets/config/manifest.js index ddd546a..b06fc42 100644 --- a/app/assets/config/manifest.js +++ b/app/assets/config/manifest.js @@ -2,3 +2,4 @@ //= link_directory ../stylesheets .css //= link_tree ../../javascript .js //= link_tree ../../../vendor/javascript .js +//= link_tree ../builds diff --git a/app/assets/tailwind/application.css b/app/assets/tailwind/application.css new file mode 100644 index 0000000..4ba672b --- /dev/null +++ b/app/assets/tailwind/application.css @@ -0,0 +1,18 @@ +@import "tailwindcss"; + +@theme { + /* dark blue */ + --color-deepcove: #04153E; + /* medium dark blue */ + --color-bluetang: #2A4B6F; + /* bright blue */ + --color-atmosphere: #0096E0; + /* light blue */ + --color-bluemana: #6AC8F1; + /* platinum */ + --color-platinum: #E0E0E0; + /* copper */ + --color-copper: #B06E30; + /* bronze */ + --color-bronze: #D38F4A; +} diff --git a/app/controllers/employer_setup_controller.rb b/app/controllers/employer_setup_controller.rb new file mode 100644 index 0000000..30fc010 --- /dev/null +++ b/app/controllers/employer_setup_controller.rb @@ -0,0 +1,191 @@ +class EmployerSetupController < ApplicationController + def new + @top_form = EmployerSetupForm.new(session[:employer_setup_data]) + 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 + end + + def create + @top_form = EmployerSetupForm.new(session[:employer_setup_data]) + if @top_form.current_step != 'summary' + if process_step(@top_form.current_step) + session[:employer_setup_data]['current_step'] = @top_form.next_step + redirect_to new_employer_setup_path + else + render @top_form.current_step_view + end + else + if @top_form.save + session.delete(:employer_setup_data) + redirect_to root_path, notice: "Employer setup successfully!" + else + render @top_form.current_step_view + end + end + + case @top_form.current_step + when 'general_information' + @form = EmployerSetupGeneralInformationForm.new(general_information_params) + if @form.valid? + session[:employer_setup_data]['general_information_data'] = general_information_params + session[:employer_setup_data]['current_step'] = @top_form.next_step + redirect_to new_employer_setup_path + else + render @top_form.current_step_view + end + when 'plans' + @form = EmployerSetupPlansForm.new(plans_params) + if @form.valid? + session[:employer_setup_data]['plans_data'] = plans_params + session[:employer_setup_data]['current_step'] = @top_form.next_step + redirect_to new_employer_setup_path + else + render @top_form.current_step_view + end + when 'network_exceptions' + @form = EmployerSetupNetworkExceptionsForm.new(network_exceptions_params) + if @form.valid? + session[:employer_setup_data]['network_exceptions_data'] = network_exceptions_params + session[:employer_setup_data]['current_step'] = @top_form.next_step + redirect_to new_employer_setup_path + else + render @top_form.current_step_view + end + when 'summary' + @form = EmployerSetupForm.new(session[:employer_setup_data]) + if @form.save + session.delete(:employer_setup_data) + redirect_to root_path, notice: "Employer setup successfully!" + else + render @top_form.current_step_view + end + end + end + + def update + @form = RegistrationForm.new(registration_params) + + if params[:back_button] + @form.current_step = @form.previous_step + elsif params[:skip_newsletter] + @form.current_step = @form.next_step # Skip newsletter step + end + + render :new + end + + private + + def general_information_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 plans_params + params.require(:employer_setup_plans_form).permit( + plans: permited_plans_keys, + benefit_descs: benefit_sequence_keys + ) + end + + def network_exceptions_params + params.require(:employer_setup_network_exceptions_form).permit( + network_exceptions: [:network_logo, exceptions: [:type, :value]], + ) + 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 + + + + + + session[:employer_setup_data]['current_step'] = @top_form.next_step + redirect_to new_employer_setup_path + else + render @top_form.current_step_view + end + end + + when 'general_information' + @form = EmployerSetupGeneralInformationForm.new(general_information_params) + if @form.valid? + session[:employer_setup_data]['general_information_data'] = general_information_params + session[:employer_setup_data]['current_step'] = @top_form.next_step + redirect_to new_employer_setup_path + else + render @top_form.current_step_view + end + + # def employer_setup_params + # params.require(:employer_setup_form).permit( + # :current_step, + # :name, + # :employer_logo, + # :group_number, + # :pl_plan_key, + # :effect_date, + # :number_of_plans, + # :network, + # :number_of_additional_network_logos, + # network_exceptions: [:network_logo, exceptions: [:type, :value]], + # plans: permited_plans_keys, + # benefit_descs: benefit_sequence_keys + # ) + # end + + def benefit_sequence_keys + (1..14).map { |i| i.to_s.to_sym } + end + + def permited_plans_keys + benefit_sequence_keys.push(:plan_id) + end + + # def plans_params + # plans_keys = params[:plans]&.keys || [] + + # plans_keys.each_with_object({}) do |key, hash| + # if key == 'benefit_descs' || key.match?(/^plan_\d$/) + # hash[key.to_sym] = permited_plan_param_list + # end + # end + # end + + # def permited_plan_param_list + # (1..14).map { |i| i.to_s.to_sym }.push(:plan_id) + # end +end diff --git a/app/controllers/employer_setup_controller_old.rb b/app/controllers/employer_setup_controller_old.rb new file mode 100644 index 0000000..6837bc4 --- /dev/null +++ b/app/controllers/employer_setup_controller_old.rb @@ -0,0 +1,109 @@ +class EmployerSetupController < ApplicationController + def new + @employer_data = session[:employer_data] || {} + # @id_card_templates = IdCardTemplate.where.not(title: "BLANK") + # @id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits.sort_by(&:sequence) + end + + def create_employer + @employer_data = {employer: {}} + @employer_data[:employer].merge!(params.require(:employer).permit( + :name, + :group_number, + :pl_plan_key, + :effect_date + )) + @employer_data[:employer].merge!(params.permit(:number_of_plans)) + + session[:employer_data] = @employer_data + puts session[:employer_data] + redirect_to action: :plans + end + + def plans + @employer_data = session[:employer_data] || {} + @id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK") + @id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence) + end + + def create_plans + @employer_data = session[:employer_data] || {} + @employer_data.merge!(params.require(:plans).permit(plans_params)) + session[:employer_data] = @employer_data + redirect_to action: :networks + end + + def networks + @employer_data = session[:employer_data] || {} + + end + + def create_provider_networks + @employer_data = session[:employer_data] || {} + @employer_data.merge!(params.require(:plans).permit(plans_params)) + session[:employer_data] = @employer_data + redirect_to action: :networks + end + + + def process_bad_name + @final_data = session[:employer_data] + + # Vhcs::HlPlanCode.create( + # group_number: @final_data['employer']['name'], + # medical_number: @final_data['employer']['group_number'], + # dental_number: ' ', + # plan_key: @final_data['employer']['pl_plan_key'], + # effect_date: @final_data['employer']['effect_date'] + # ) + + # default = Vhcs::HLRXCrosRef.find_by(pl_plan_key: 52) + + # Vhcs::HLRXCrosRef.create( + # group_no: @final_data['employer']['group_number'], + # rx_group_id: @final_data['employer']['group_number'], + # help_desk: default.help_desk, + # customer_service: default.customer_service, + # web_url: default.web_url, + # pl_plan_key: @final_data['employer']['pl_plan_key'] + # ) + + # plans_data = @final_data['plans'] + # benefit_descs = plans_data.delete('benefit_descs') + + # plans_data.each do |key, value| + # plan_id = value.delete('plan_id') + # value.each do |key2, value2| + # Vhcs::HLEgglestonCardBenefit.create( + # plan_id: plan_id, + # benefit_desc: benefit_descs[key2], + # benefit: value2, + # sequence: key2, + # plan_key: @final_data['employer']['pl_plan_key'] + # ) + # end + + # end + + # Create or update your model with @final_data + # Clear the session data after successful save + session[:employer_data] = nil + # Redirect to a success page + end + + private + + def plans_params + plans_keys = params[:plans]&.keys || [] + + plans_keys.each_with_object({}) do |key, hash| + if key == 'benefit_descs' || key.match?(/^plan_\d$/) + hash[key.to_sym] = permited_plan_param_list + end + end + end + + def permited_plan_param_list + (1..14).map { |i| i.to_s.to_sym }.push(:plan_id) + end +end diff --git a/app/controllers/employer_setup_controller_pre_split.rb b/app/controllers/employer_setup_controller_pre_split.rb new file mode 100644 index 0000000..964df31 --- /dev/null +++ b/app/controllers/employer_setup_controller_pre_split.rb @@ -0,0 +1,89 @@ +class EmployerSetupController < ApplicationController + def new + # session.delete(:employer_setup_data) + @form = EmployerSetupForm.new(session[:employer_setup_data]) + if @form.current_step == "plans" + @id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK") + @id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence) + end + puts session[:employer_setup_data] + render "employer_setup/#{@form.current_step}" # Renders the view for the current step + end + + def create + filtered_params = employer_setup_params.except(:validation_context) + @form = EmployerSetupForm.new(filtered_params) + + if @form.current_step == "general" && @form.valid?(:general_info) + # @form.current_step = "plans" + @form.current_step = "networks" # TESTING, Change Back + session[:employer_setup_data] = @form.attributes.slice("current_step", "name", "employer_logo", "group_number", "pl_plan_key", "effect_date", "number_of_plans", "network", "number_of_additional_network_logos") + redirect_to new_employer_setup_path # Redirect to the next step + elsif @form.current_step == "plans" && @form.valid?(:plan_info) + if @form.number_of_additional_network_logos == 0 + next_step = "summary" + else + next_step = "networks" + end + @form.current_step = next_step + session[:employer_setup_data].merge!(@form.attributes.slice("current_step", "plans", "benefit_descs")) + redirect_to new_employer_setup_path + # @form = UserOnboardingForm.new(session[:employer_setup_data]) # Re-initialize with all data + elsif @form.current_step == "networks" && @form.valid?(:network_info) + @form.current_step = "summary" + session[:employer_setup_data].merge!(@form.attributes.slice("current_step", "network_exceptions")) + redirect_to new_employer_setup_path + elsif @form.current_step == "summary" + puts @form.attributes + if @form.save + session.delete(:employer_setup_data) # Clear session data after successful save + redirect_to root_path, notice: "Employer setup successfully!" + else + render "employer_setup/summary" # Render step two again with errors + end + else + render "employer_setup/#{@form.current_step}" # Render the current step again with errors + end + end + + private + + def employer_setup_params + params.require(:employer_setup_form).permit( + :current_step, + :name, + :employer_logo, + :group_number, + :pl_plan_key, + :effect_date, + :number_of_plans, + :network, + :number_of_additional_network_logos, + network_exceptions: [:network_logo, exceptions: [:type, :value]], + plans: permited_plans_keys, + benefit_descs: benefit_sequence_keys + ) + end + + def benefit_sequence_keys + (1..14).map { |i| i.to_s.to_sym } + end + + def permited_plans_keys + benefit_sequence_keys.push(:plan_id) + end + + def plans_params + plans_keys = params[:plans]&.keys || [] + + plans_keys.each_with_object({}) do |key, hash| + if key == 'benefit_descs' || key.match?(/^plan_\d$/) + hash[key.to_sym] = permited_plan_param_list + end + end + end + + def permited_plan_param_list + (1..14).map { |i| i.to_s.to_sym }.push(:plan_id) + end +end diff --git a/app/controllers/id_card_benefits_templates_controller.rb b/app/controllers/id_card_benefits_templates_controller.rb new file mode 100644 index 0000000..5f4ec81 --- /dev/null +++ b/app/controllers/id_card_benefits_templates_controller.rb @@ -0,0 +1,89 @@ +class IdCardBenefitsTemplatesController < ApplicationController + skip_before_action :verify_authenticity_token + + def new_id_card_template + @id_card_templates = IdCardTemplate.where.not(title: "BLANK") + @id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits.sort_by(&:sequence) + end + + def create_id_card_template + @id_card_template = IdCardTemplate.create(title: params[:title]) + + params[:benefits].each do |key, value| + IdCardTemplateBenefit.create( + sequence: key, + benefit_desc: value["desc"], + benefit: value["value"], + id_card_template: @id_card_template + ) + + end + + respond_to do |format| + if @id_card_template.save && @id_card_template.id_card_template_benefits.length == 14 + format.html { redirect_to '/dev_tools/new_id_card_setup', notice: "Template was successfully created." } + # format.json { render :show, status: :created, location: @employer } + else + format.html { render :new_id_card_template, status: :unprocessable_entity } + # format.json { render json: @employer.errors, status: :unprocessable_entity } + end + end + end + + def new_id_card_setup + @id_card_templates = IdCardTemplate.where.not(title: "BLANK") + @id_card_template_benefits = IdCardTemplate.find_by(title: "BLANK").id_card_template_benefits + end + + def get_templates_benefits + @id_card_benefits = IdCardBenefitsTemplate.find(params[:id]).id_card_benefits + render json: @id_card_benefits.as_json + end + + def create_id_card_setup + employer_general = params['general'] + hl_plan_code = Vhcs::HlPlanCode.new( + group_number: employer_general['group_number'], + medical_number: employer_general['group_number'], + dental_number: '', + plan_key: employer_general['pl_plan_key'], + effect_date: employer_general['effect_date'] + ) + + # Replace fairos_info with template like for benefits + fairos_info = Vhcs::HLRXCrosRef.where(pl_plan_key: 52).first + hlrx_cros_ref = Vhcs::HLRXCrosRef.new( + group_no: employer_general['group_number'], + rx_group_id: employer_general['group_number'], + help_desk: fairos_info.help_desk, + customer_service: fairos_info.customer_service, + web_url: fairos_info.web_url, + pl_plan_key: employer_general['pl_plan_key'] + ) + + number_of_plans = params[:number_of_plans].to_i + + number_of_plans.each do |i| + value['benefits'].each do |ben_key, ben_value| + Vhcs::HLEgglestonCardBenefit.create( + plan_id: value['plan_id'], + benefit_desc: ben_value["desc"], + benefit: ben_value["value"], + sequence: ben_key, + plan_key: employer_general['pl_plan_key'] + ) + end + end + + respond_to do |format| + if hl_plan_code.save && hlrx_cros_ref.save + format.html { redirect_to '/dev_tools/new_id_card_setup', notice: "Card setup was successfully created." } + # format.json { render :show, status: :created, location: @employer } + else + format.html { render :new_id_card_setup, status: :unprocessable_entity } + # format.json { render json: @employer.errors, status: :unprocessable_entity } + end + end + end + +end diff --git a/app/form_builders/tailwind_form_builder.rb b/app/form_builders/tailwind_form_builder.rb new file mode 100644 index 0000000..b680ce2 --- /dev/null +++ b/app/form_builders/tailwind_form_builder.rb @@ -0,0 +1,106 @@ +class TailwindFormBuilder < ActionView::Helpers::FormBuilder + class_attribute :text_field_helpers, default: field_helpers - [:label, :check_box, :radio_button, :fields_for, :fields, :hidden_field, :file_field] + # leans on the FormBuilder class_attribute `field_helpers` + # you'll want to add a method for each of the specific helpers listed here if you want to style them + + TEXT_FIELD_STYLE = "bg-gray-200 rounded py-2 px-4 text-bluetang font-semibold leading-tight focus:outline-none focus:bg-white".freeze + SELECT_FIELD_STYLE = "block bg-gray-200 text-gray-700 py-2 px-4 rounded leading-tight focus:outline-none focus:bg-white".freeze + SUBMIT_BUTTON_STYLE = "shadow bg-bronze focus:shadow-outline focus:outline-none text-white font-bold py-2 px-4 rounded hover:bg-copper".freeze + + text_field_helpers.each do |field_method| + class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1 + def #{field_method}(method, options = {}) + if options.delete(:tailwindified) + super + else + text_like_field(#{field_method.inspect}, method, options) + end + end + RUBY_EVAL + end + + def submit(value = nil, options = {}) + custom_opts, opts = partition_custom_opts(options) + classes = apply_style_classes(SUBMIT_BUTTON_STYLE, custom_opts) + + super(value, {class: classes}.merge(opts)) + end + + def select(method, choices = nil, options = {}, html_options = {}, &block) + custom_opts, opts = partition_custom_opts(options) + classes = apply_style_classes(SELECT_FIELD_STYLE, custom_opts, method) + + labels = labels(method, custom_opts[:label], options) + field = super(method, choices, opts, html_options.merge({class: classes}), &block) + + labels + field + end + + private + + def text_like_field(field_method, object_method, options = {}) + custom_opts, opts = partition_custom_opts(options) + + classes = apply_style_classes(TEXT_FIELD_STYLE, custom_opts, object_method) + + field = send(field_method, object_method, { + class: classes, + title: errors_for(object_method)&.join(" ") + }.compact.merge(opts).merge({tailwindified: true})) + + labels = labels(object_method, custom_opts[:label], options) + + labels + field + end + + def labels(object_method, label_options, field_options) + label = tailwind_label(object_method, label_options, field_options) + error_label = error_label(object_method, field_options) + + @template.content_tag("div", label + error_label, {class: "flex flex-col items-start"}) + end + + def tailwind_label(object_method, label_options, field_options) + text, label_opts = if label_options.present? + [label_options[:text], label_options.except(:text)] + else + [nil, {}] + end + + label_classes = label_opts[:class] || "block text-platinum font-bold md:text-right mb-1 md:mb-0 pr-4" + label_classes += " text-yellow-800 dark:text-yellow-400" if field_options[:disabled] + label(object_method, text, { + class: label_classes + }.merge(label_opts.except(:class))) + end + + def error_label(object_method, options) + if errors_for(object_method).present? + error_message = @object.errors[object_method].collect(&:titleize).join(", ") + tailwind_label(object_method, {text: error_message, class: " font-bold text-red-500"}, options) + end + end + + def border_color_classes(object_method) + if errors_for(object_method).present? + " border-2 border-red-400 focus:border-rose-200" + else + " border border-platinum focus:border-yellow-700" + end + end + + def apply_style_classes(classes, custom_opts, object_method = nil) + classes + border_color_classes(object_method) + " #{custom_opts[:class]}" + end + + CUSTOM_OPTS = [:label, :class].freeze + def partition_custom_opts(opts) + opts.partition { |k, v| CUSTOM_OPTS.include?(k) }.map(&:to_h) + end + + def errors_for(object_method) + return unless @object.present? && object_method.present? + + @object.errors[object_method] + end +end \ No newline at end of file diff --git a/app/forms/employer_setup_form.rb b/app/forms/employer_setup_form.rb new file mode 100644 index 0000000..d8cb4ee --- /dev/null +++ b/app/forms/employer_setup_form.rb @@ -0,0 +1,57 @@ +class EmployerSetupForm + include ActiveModel::Model + include ActiveModel::Attributes + + FIRST_STEP = "general_information" + + attribute :current_step, :string, default: FIRST_STEP + attribute :general_information_data + attribute :plans_data + attribute :network_exceptions_data + + def initialize(params = {}) + unless self.steps.first == FIRST_STEP + raise StepMisalignmentError, "FIRST_STEP does not match first entry in steps" + end + @general_information_data = EmployerSetupGeneralInformationForm.new(attributes[:general_information_data]) + @plans_data = EmployerSetupPlansForm.new(attributes[:plans_data]) + @network_exceptions_data = EmployerSetupNetworkExceptionsForm.new(attributes[:network_exceptions_data]) + end + + def steps + %w[general_information plans network_exceptions summary] + end + + def current_step_view + "employer_setup/#{self.current_step}" + end + + def next_step + index = steps.index(current_step) + if index && index < steps.length - 1 + if steps[index + 1] == 'network_exceptions' && general_information_data.number_of_additional_network_logos == 0 + steps[index + 2] + else + steps[index + 1] + end + end + end + + def previous_step + index = steps.index(current_step) + steps[index - 1] if index && index > 0 + end + + def save + if valid? + pl_plan_key = attributes[:general_information_data][:pl_plan_key] + EmployerSetupGeneralInformationForm.new(attributes[:general_information_data]).save + 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 \ No newline at end of file diff --git a/app/forms/employer_setup_form_pre_split.rb b/app/forms/employer_setup_form_pre_split.rb new file mode 100644 index 0000000..dad07a2 --- /dev/null +++ b/app/forms/employer_setup_form_pre_split.rb @@ -0,0 +1,62 @@ +class EmployerSetupForm + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :current_step, :string, default: "general" + attribute :name, :string + attribute :employer_logo + attribute :group_number, :string + attribute :pl_plan_key, :string + attribute :effect_date, :string + attribute :number_of_plans, :integer + attribute :network, :string + attribute :number_of_additional_network_logos, :integer + attribute :plans, array: true, default: -> { [] } +# attribute :benefit_descs, :hash, default: -> { {} } + attribute :network_exceptions, array: true, default: -> { [] } + + attr_accessor :benefit_descs + + # Define validations based on the current step + with_options on: :general_info do + validates :name, presence: true + validates :employer_logo, presence: true + validates :group_number, presence: true + validates :pl_plan_key, presence: true + validates :effect_date, presence: true + validates :number_of_plans, presence: true + validates :network, presence: true + # validates :number_of_additional_network_logos, presence: true if network = "cigna+" + end + + with_options on: :plan_info do + validates :plans, presence: true + # validates :benefit_descs, presence: true + end + + with_options on: :network_info do + # validates :network_exceptions, presence: true if number_of_additional_network_logos > 0 + end + +# def initialize(params = {}) +# super(params) +# # Ensure the attribute is a hash after initialization +# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs] +# end + + def benefit_descs + @benefit_descs ||= {} + end + + def save + # Implement logic to save data to models after all steps are complete + # For example, create a User record with the collected data + if valid? && step == total_steps + # User.create!(name: name, email: email, password: password) + true + else + false + end + end + +end \ No newline at end of file diff --git a/app/forms/employer_setup_general_information_form.rb b/app/forms/employer_setup_general_information_form.rb new file mode 100644 index 0000000..8182d46 --- /dev/null +++ b/app/forms/employer_setup_general_information_form.rb @@ -0,0 +1,72 @@ +class EmployerSetupGeneralInformationForm + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :name, :string + attribute :employer_logo + attribute :group_number, :string + attribute :dental, :boolean + attribute :pl_plan_key, :string + attribute :effect_date, :string + attribute :number_of_plans, :integer + attribute :network, :string + attribute :number_of_additional_network_logos, :integer + + validates :name, presence: true + validates :employer_logo, presence: true + validates :group_number, presence: true + validates :pl_plan_key, presence: true + validates :effect_date, presence: true + validates :number_of_plans, presence: true + validates :network, presence: true + # validates :number_of_additional_network_logos, presence: true if network = "cigna+" + +# def initialize(params = {}) +# super(params) +# # Ensure the attribute is a hash after initialization +# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs] +# end + + def save + # Implement logic to save data to models after all steps are complete + # For example, create a User record with the collected data + if valid? + hl_plan_code = Vhcs::HlPlanCode.create!( + group_number: group_number, + medical_number: group_number, + dental_number: '', + plan_key: pl_plan_key, + effect_date: effect_date + ) + + # Replace fairos_info with template like for benefits + fairos_info = Vhcs::HLRXCrosRef.where(pl_plan_key: 52).first + hlrx_cros_ref = Vhcs::HLRXCrosRef.create!( + group_no: group_number, + rx_group_id: group_number, + help_desk: fairos_info.help_desk, + customer_service: fairos_info.customer_service, + web_url: fairos_info.web_url, + pl_plan_key: pl_plan_key + ) + + web_employer = BrittonWeb::Employers.create!( + pl_plan_key: pl_plan_key, + dental_plan: dental, + single_card_template: 'FairosRxIDCard', + logo: employer_logo.filename + ) + + BrittonWeb::NetworkLogos.create!( + employer: web_employer, + net_logo: network, + default: true + ) + + true + else + false + end + end + +end \ No newline at end of file diff --git a/app/forms/employer_setup_network_exceptions_form.rb b/app/forms/employer_setup_network_exceptions_form.rb new file mode 100644 index 0000000..fd87609 --- /dev/null +++ b/app/forms/employer_setup_network_exceptions_form.rb @@ -0,0 +1,46 @@ +class EmployerSetupNetworkExceptionsForm + include ActiveModel::Model + include ActiveModel::Attributes + + Network_exception = Struct.new(:network_logo, :exceptions) + attribute :network_exceptions, :array_of_items, default: -> { [] } + + # validates :network_exceptions, presence: true if number_of_additional_network_logos > 0 + +# def initialize(params = {}) +# super(params) +# # Ensure the attribute is a hash after initialization +# @benefit_descs = params[:benefit_descs].to_h if params[:benefit_descs] +# end + + def save(pl_plan_key) + # Implement logic to save data to models after all steps are complete + # For example, create a User record with the collected data + if valid? + employer = BrittonWeb::Employers.find_by(pl_plan_key: pl_plan_key) + + network_exceptions.each do |ne| + BrittonWeb::NetworkLogos.create!( + employer: employer, + net_logo: ne.network_logo, + exception_type: ne.type, + exception_value: ne.value, + default: false + ) + end + true + else + false + end + end + +end + + +class NetworkException + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :network_logo + attribute :exceptions, array: true, default: -> { [] } +end \ No newline at end of file diff --git a/app/forms/employer_setup_plans_form.rb b/app/forms/employer_setup_plans_form.rb new file mode 100644 index 0000000..1261e2b --- /dev/null +++ b/app/forms/employer_setup_plans_form.rb @@ -0,0 +1,49 @@ +class EmployerSetupPlansForm + include ActiveModel::Model + include ActiveModel::Attributes + + attribute :plans, array: true, default: -> { [] } +# attribute :benefit_descs, :hash, default: -> { {} } + + attr_accessor :id_card_templates + attr_accessor :id_card_template_benefits + attr_accessor :benefit_descs + + validates :plans, presence: true + # validates :benefit_descs, presence: true + + + def initialize(params = {}) + super(params) + + @id_card_templates = IdCardBenefitsTemplate.where.not(title: "BLANK") + @id_card_template_benefits = IdCardBenefitsTemplate.find_by(title: "BLANK").id_card_benefits.sort_by(&:sequence) + end + + # def benefit_descs + # @benefit_descs ||= {} + # end + + def save(pl_plan_key) + # Implement logic to save data to models after all steps are complete + # For example, create a User record with the collected data + if valid? + plans.each do |plan| + plan_id = plan.delete(:plan_id) + plan.each do |key, value| + Vhcs::HLEgglestonCardBenefit.create( + plan_id: plan_id, + benefit_desc: benefit_descs["#{key}"], + benefit: value, + sequence: key, + plan_key: pl_plan_key + ) + end + end + true + else + false + end + end + +end \ No newline at end of file diff --git a/app/helpers/id_card_employers_helper.rb b/app/helpers/id_card_employers_helper.rb new file mode 100644 index 0000000..e5e3a5f --- /dev/null +++ b/app/helpers/id_card_employers_helper.rb @@ -0,0 +1,2 @@ +module IdCardEmployersHelper +end diff --git a/app/javascript/application.js b/app/javascript/application.js index 04d0ac4..a31a955 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -3,5 +3,3 @@ import "@hotwired/turbo-rails" import "controllers" import "trix" import "@rails/actiontext" - -console.log('Hello World from application.js'); diff --git a/app/javascript/controllers/application.js b/app/javascript/controllers/application.js index d865bdd..1213e85 100644 --- a/app/javascript/controllers/application.js +++ b/app/javascript/controllers/application.js @@ -7,5 +7,3 @@ application.debug = false window.Stimulus = application export { application } - -console.log('Hello World from controllers/application.js'); diff --git a/app/javascript/controllers/benefits_template_picker_controller.js b/app/javascript/controllers/benefits_template_picker_controller.js new file mode 100644 index 0000000..02d5fb2 --- /dev/null +++ b/app/javascript/controllers/benefits_template_picker_controller.js @@ -0,0 +1,38 @@ +import { Controller } from "@hotwired/stimulus"; + +export default class extends Controller { + 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"]; + + async fetchData(event) { + const templateId = event.target.value; + if (!templateId) { + this.clearFields(); + return; + } + + const url = "/id_card_benefits_templates/get_templates_benefits/:id".replace(':id', templateId); + const response = await fetch(url); + const templateBenefitsData = await response.json(); + + + + this.nameTarget.value = templateData.name; + this.descriptionTarget.value = templateData.description; + } + + clearFields() { + this.nameTarget.value = ''; + this.descriptionTarget.value = ''; + } + + updateFields(templateBenefitsData) { + templateBenefitsData.forEach(function(benefit) { + const propertyName = `benefit_${benefit.sequence}` + this[propertyName].value = benefit.benefit + }); + } +} + +// this[propertyName] +// const propertyName = `${valueName}Value`; diff --git a/app/javascript/controllers/dynamic_plan_fields_controller.js b/app/javascript/controllers/dynamic_plan_fields_controller.js new file mode 100644 index 0000000..b935f54 --- /dev/null +++ b/app/javascript/controllers/dynamic_plan_fields_controller.js @@ -0,0 +1,37 @@ +import { Controller } from "@hotwired/stimulus"; + +export default class extends Controller { + static targets = ["numberInput", "planFieldsContainer", "template"]; + + connect() { + this.updatePlanFields(); + } + + updatePlanFields() { + const desiredCount = parseInt(this.numberInputTarget.value || 1, 10); + const currentCount = this.planFieldsContainerTarget.children.length; + + if (desiredCount > currentCount) { + this.addPlanFields(desiredCount - currentCount); + } else if (desiredCount < currentCount) { + this.removePlanFields(currentCount - desiredCount); + } + } + + addPlanFields(count) { + for (let i = 0; i < count; i++) { + const newPlanField = this.templateTarget.content.cloneNode(true); + // Replace '__INDEX__' with a unique value for nested attributes + // e.g., using Date.now() or a counter + const uniqueIndex = Date.now() + i; + newPlanField.innerHTML = newPlanField.innerHTML.replace(/__INDEX__/g, uniqueIndex); + this.planFieldsContainerTarget.appendChild(newPlanField); + } + } + + removePlanFields(count) { + for (let i = 0; i < count; i++) { + this.planFieldsContainerTarget.lastElementChild.remove(); + } + } +} \ No newline at end of file diff --git a/app/javascript/controllers/form_toggle_controller.js b/app/javascript/controllers/form_toggle_controller.js new file mode 100644 index 0000000..dda434d --- /dev/null +++ b/app/javascript/controllers/form_toggle_controller.js @@ -0,0 +1,22 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["divA"] // Add targets for all your divs + + connect() { + this.toggleDivs() // Call on connect to set initial state + } + + toggleDivs() { + const selectedValue = this.element.querySelector('select').value; + console.log("sv: ") + + // Hide all divs first + this.divATarget.classList.add("hidden"); + + // Show the relevant div based on selection + if (selectedValue === "cig+") { + this.divATarget.classList.remove("hidden"); + } + } +} \ No newline at end of file diff --git a/app/models/application_record.rb b/app/models/application_record.rb index 08dc537..caaf180 100644 --- a/app/models/application_record.rb +++ b/app/models/application_record.rb @@ -2,4 +2,6 @@ class ApplicationRecord < ActiveRecord::Base primary_abstract_class + + establish_connection :dev_tools end diff --git a/app/models/article.rb b/app/models/article.rb deleted file mode 100644 index f245902..0000000 --- a/app/models/article.rb +++ /dev/null @@ -1,5 +0,0 @@ -class Article < ApplicationRecord - has_many :comments, dependent: :destroy - has_rich_text :content - validates_presence_of :title -end diff --git a/app/models/comment.rb b/app/models/comment.rb deleted file mode 100644 index 48e21c4..0000000 --- a/app/models/comment.rb +++ /dev/null @@ -1,4 +0,0 @@ -class Comment < ApplicationRecord - belongs_to :article - broadcasts_to :article -end diff --git a/app/models/id_card_benefit.rb b/app/models/id_card_benefit.rb new file mode 100644 index 0000000..f903ec7 --- /dev/null +++ b/app/models/id_card_benefit.rb @@ -0,0 +1,3 @@ +class IdCardBenefit < ApplicationRecord + belongs_to :id_card_benefits_template +end diff --git a/app/models/id_card_benefits_template.rb b/app/models/id_card_benefits_template.rb new file mode 100644 index 0000000..f8ffe76 --- /dev/null +++ b/app/models/id_card_benefits_template.rb @@ -0,0 +1,5 @@ +class IdCardBenefitsTemplate < ApplicationRecord + + has_many :id_card_benefits + +end diff --git a/app/models/vhcs/hl_eggleston_card_benefit.rb b/app/models/vhcs/hl_eggleston_card_benefit.rb new file mode 100644 index 0000000..dfa735f --- /dev/null +++ b/app/models/vhcs/hl_eggleston_card_benefit.rb @@ -0,0 +1,15 @@ +module Vhcs + class HlEgglestonCardBenefit < VhcsRecord + + self.table_name = 'HLEgglestonCardBenefit' + + alias_attribute :id, :Id + alias_attribute :plan_id, :PlanId + alias_attribute :benefit_desc, :BenefitDesc + alias_attribute :benefit, :Benefit + alias_attribute :sequence, :Sequence + alias_attribute :plan_key, :PlanKey + + + end +end \ No newline at end of file diff --git a/app/models/vhcs/hl_plan_code.rb b/app/models/vhcs/hl_plan_code.rb new file mode 100644 index 0000000..5a09301 --- /dev/null +++ b/app/models/vhcs/hl_plan_code.rb @@ -0,0 +1,14 @@ +module VHCS + class HlPlanCode < VhcsRecord + + self.table_name = 'HlPlanCode' + + alias_attribute :id, :ID + alias_attribute :group_number, :GroupNumber + alias_attribute :medical_number, :MedicalNumber + alias_attribute :dental_number, :DentalNumber + alias_attribute :plan_key, :PlanKey + alias_attribute :effect_date, :EffectDate + + end +end \ No newline at end of file diff --git a/app/models/vhcs/hlrx_cros_ref.rb b/app/models/vhcs/hlrx_cros_ref.rb new file mode 100644 index 0000000..a39c19f --- /dev/null +++ b/app/models/vhcs/hlrx_cros_ref.rb @@ -0,0 +1,15 @@ +module Vhcs + class HLRXCrosRef < VhcsRecord + + self.table_name = 'HLRXCrosRef' + + alias_attribute :group_no, :GroupNo + alias_attribute :rx_group_id, :RXGroupID + alias_attribute :help_desk, :HelpDesk + alias_attribute :customer_service, :CustomerService + alias_attribute :web_url, :WebUrl + alias_attribute :pl_plan_key, :PLPlanKey + + + end +end \ No newline at end of file diff --git a/app/models/vhcs_record.rb b/app/models/vhcs_record.rb new file mode 100644 index 0000000..2f37be3 --- /dev/null +++ b/app/models/vhcs_record.rb @@ -0,0 +1,5 @@ +class VhcsRecord < ActiveRecord::Base + self.abstract_class = true +# establish_connection :vhcs + connects_to database: { writing: :vhcs, reading: :vhcs } +end \ No newline at end of file diff --git a/app/types/array_of_items_type.rb b/app/types/array_of_items_type.rb new file mode 100644 index 0000000..64ce32e --- /dev/null +++ b/app/types/array_of_items_type.rb @@ -0,0 +1,23 @@ +class ArrayOfItemsType < ActiveModel::Type::Value + # The `cast` method is used to convert an incoming value into the desired type. + def cast(value) + return unless value.present? + + Array.wrap(value).map do |item_data| + # 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. + if item_data.is_a?(Hash) + Item.new(item_data) + else + item_data # Return the item as-is if it's already an object + end + end + end + + # This method is used when defining the type to convert it to a string for serialization. + def serialize(value) + value + end +end + +ActiveModel::Type.register(:array_of_items, ArrayOfItemsType) \ No newline at end of file diff --git a/app/views/employer_setup/general.html.erb b/app/views/employer_setup/general.html.erb new file mode 100644 index 0000000..4eb6c28 --- /dev/null +++ b/app/views/employer_setup/general.html.erb @@ -0,0 +1,56 @@ +
+

New Employer Setup

+

General Information

+ <%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %> +
+
+
+ <%= f.text_field :name, label: { text: "Employer Name" }, class: "w-full" %> +
+
+ <%= f.text_field :group_number, label: { text: "Group/Medical Number" }, class: "w-full" %> +
+
+ <%= f.check_box :dental %> +
+
+
+
+ <%= f.text_field :pl_plan_key, label: { text: "Pl Plan Key" }, class: "w-full" %> +
+
+ <%= f.text_field :effect_date, label: { text: "Effective Date" }, class: "w-full" %> +
+
+
+
+ <%= f.select :number_of_plans, options_for_select((1..6).to_a), label: { text: "Number of Plans" }, class: "w-1/3" %> +
+
+ <%= 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 :number_of_additional_network_logos, options_for_select((0..6).to_a), label: { text: "Number of Additional Network Logos" }, class: "w-1/3" %> +
+
+
+ + No file chosen + <%= f.file_field :employer_logo, class: "hidden", id: "file_upload_input" %> +
+
+ <%= f.submit "Continue to Plans" %> +
+
+ <% end %> +
+ + + \ No newline at end of file diff --git a/app/views/employer_setup/networks.html.erb b/app/views/employer_setup/networks.html.erb new file mode 100644 index 0000000..366bc2e --- /dev/null +++ b/app/views/employer_setup/networks.html.erb @@ -0,0 +1,41 @@ +
+

New Employer Setup

+

Provider Network

+ <%= 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| %> +
+
+ + No file chosen + <%= network_fields.file_field :network_logo, class: "hidden", id: "file_upload_input" %> +
+ <% 2.to_i.times do |j| %> + <%= network_fields.fields_for :exceptions do |exception_fields| %> +
+
+ <%= exception_fields.select :type, options_for_select(["Zipcode","State"]), label: { text: "Exception Type" }, prompt: "Select Type", class: "w-full" %> +
+
+ <%= exception_fields.text_field :value, label: { text: "Exception Value" }, class: "w-full" %> +
+
+ <% end %> + <% end %> +
+ <% end %> + <% end %> +
+ <%= f.submit "Continue to Summary" %> +
+ <% end %> +
+ + \ No newline at end of file diff --git a/app/views/employer_setup/plans.html copy.erb b/app/views/employer_setup/plans.html copy.erb new file mode 100644 index 0000000..1e691c7 --- /dev/null +++ b/app/views/employer_setup/plans.html copy.erb @@ -0,0 +1,38 @@ +
+

New Employer Setup

+ <%= form_with url: 'create_plans', method: :post do |form| %> +
+
+ <% @id_card_template_benefits.each do |bene| %> +
+ <%= form.text_field "plans[benefit_descs][#{bene.sequence}]", label: { text: "Benefit Description" }, value: "#{bene.benefit_desc}" %> +
+ <% end %> +
+ <% @employer_data['employer']['number_of_plans'].to_i.times do |i| %> +
+
+ <%= form.text_field "plans[plan_#{i}][plan_id]", label: { text: "Plan Id" } %> +
+
+ +
+ <% @id_card_template_benefits.each do |bene| %> +
+
+ <%= form.text_field "plans[plan_#{i}][#{bene.sequence}]", label: { text: "Benefit Value" }, data: { benefits_template_picker_target: "benefit_#{bene.sequence}" } %> +
+
+ <% end %> +
+ <% end %> +
+ <%= form.submit "Summary" %> +
+ <% end %> + diff --git a/app/views/employer_setup/plans.html.erb b/app/views/employer_setup/plans.html.erb new file mode 100644 index 0000000..70823a8 --- /dev/null +++ b/app/views/employer_setup/plans.html.erb @@ -0,0 +1,47 @@ +
+

New Employer Setup

+

Medical Plans

+
+ <%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %> +
+
+ <% @id_card_template_benefits.each do |bene| %> + <%= f.fields_for :benefit_descs do |bd_fields| %> +
+ <%= bd_fields.text_field "#{bene.sequence}", label: { text: "Benefit Description #{bene.sequence}" }, value: "#{bene.benefit_desc}" %> +
+ <% end %> + <% end %> +
+ <% @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'] %> +
+
+
+ <%= "Plan #{i + 1}" %> +
+ <%= f.fields_for :plans do |plan_fields| %> +
+ <%= plan_fields.text_field :plan_id, label: { text: "Plan Id" }, class: "w-full" %> +
+
+ <%= 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" }} %> +
+ <% @id_card_template_benefits.each do |bene| %> +
+
+ <%= plan_fields.text_field "#{bene.sequence}", label: { text: "Benefit Value #{bene.sequence}" }, data: { benefits_template_picker_target: "benefit_#{bene.sequence}" }, class: "w-full" %> +
+
+ <% end %> + <% end %> +
+ <% end %> +
+
+ <%= f.submit "Continue to Provider Network" %> +
+ <% end %> +
+
diff --git a/app/views/employer_setup/summary.html.erb b/app/views/employer_setup/summary.html.erb new file mode 100644 index 0000000..c6f695d --- /dev/null +++ b/app/views/employer_setup/summary.html.erb @@ -0,0 +1,9 @@ +
+

New Employer Setup

+

Summary

+ <%= form_with model: @form, url: employer_setup_index_path, local: true do |f| %> +
+ <%= f.submit "Submit" %> +
+ <% end %> +
\ No newline at end of file diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb index 8d65ca5..d9cde89 100644 --- a/app/views/layouts/application.html.erb +++ b/app/views/layouts/application.html.erb @@ -5,13 +5,15 @@ <%= csrf_meta_tags %> <%= csp_meta_tag %> + <%= stylesheet_link_tag "tailwind", "data-turbo-track": "reload" %> <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> - - - <%= yield %> + +
+ <%= yield %> +
diff --git a/bin/brakeman b/bin/brakeman old mode 100755 new mode 100644 diff --git a/bin/bundle b/bin/bundle old mode 100755 new mode 100644 diff --git a/bin/dbentrypoint.sh b/bin/dbentrypoint.sh new file mode 100644 index 0000000..8939d89 --- /dev/null +++ b/bin/dbentrypoint.sh @@ -0,0 +1,11 @@ +#!/bin/bash +set -e + +# Wait for SQL Server to be ready +# You can adjust the sleep time if needed +sleep 7 + +# Run init-script with long timeout - and make it run in the background +/opt/mssql-tools/bin/sqlcmd -S localhost -U sa -P "Br1tt0nPassw0rd" -i init.sql & +# Start SQL Server +/opt/mssql/bin/sqlservr \ No newline at end of file diff --git a/bin/dev b/bin/dev new file mode 100644 index 0000000..ad72c7d --- /dev/null +++ b/bin/dev @@ -0,0 +1,16 @@ +#!/usr/bin/env sh + +if ! gem list foreman -i --silent; then + echo "Installing foreman..." + gem install foreman +fi + +# Default to port 3000 if not specified +export PORT="${PORT:-3000}" + +# Let the debug gem allow remote connections, +# but avoid loading until `debugger` is called +export RUBY_DEBUG_OPEN="true" +export RUBY_DEBUG_LAZY="true" + +exec foreman start -f Procfile.dev "$@" diff --git a/bin/docker-entrypoint b/bin/docker-entrypoint old mode 100755 new mode 100644 diff --git a/bin/docker-entrypoint-development b/bin/docker-entrypoint-development old mode 100755 new mode 100644 index 329394d..b119093 --- a/bin/docker-entrypoint-development +++ b/bin/docker-entrypoint-development @@ -4,6 +4,8 @@ set -e # Remove a potentially pre-existing server.pid for Rails. rm -f /usr/src/app/tmp/pids/server.pid +rm -rf /usr/local/bundle/cache/*.gem + echo "bundle install..." bundle check || bundle install --jobs 4 diff --git a/bin/importmap b/bin/importmap old mode 100755 new mode 100644 diff --git a/bin/rails b/bin/rails old mode 100755 new mode 100644 diff --git a/bin/rake b/bin/rake old mode 100755 new mode 100644 diff --git a/bin/rspec b/bin/rspec old mode 100755 new mode 100644 diff --git a/bin/rubocop b/bin/rubocop old mode 100755 new mode 100644 diff --git a/bin/setup b/bin/setup old mode 100755 new mode 100644 diff --git a/compose.yaml b/compose.yaml index 0c5c5cd..5ee3deb 100644 --- a/compose.yaml +++ b/compose.yaml @@ -2,41 +2,45 @@ services: web: build: context: ./ - dockerfile: development.Dockerfile - command: bash -c "rm -f tmp/pids/server.pid && bin/rails s -p 3000 -b '0.0.0.0'" + dockerfile: development3.Dockerfile + command: bash -c "rm -f tmp/pids/server.pid && bin/dev" volumes: - .:/usr/src/app - bundle:/usr/local/bundle ports: - - "3000:3000" + - "3002:3002" env_file: - .env environment: - HISTFILE=/usr/src/app/log/.bash_history + - RAILS_ENV=development + - TAILWIND_POLLING=true + tty: true + stdin_open: true depends_on: db: condition: service_healthy redis: condition: service_started db: - image: postgres:17 - ports: - - "5432:5432" - environment: - - POSTGRES_PASSWORD=changeme + build: + context: . + dockerfile: Dockerfile.db volumes: - - pg_data:/var/lib/postgresql/data + - ./mssql-data:/var/opt/mssql + ports: + - "1434:1434" healthcheck: - test: pg_isready -U postgres - interval: 2s - timeout: 5s - retries: 30 + test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-Usa", "-PBr1tt0nPassw0rd", "-Q", "select 1"] + interval: 10s + timeout: 3s + retries: 10 + start_period: 10s redis: image: redis volumes: - redis_data:/data volumes: - pg_data: redis_data: bundle: diff --git a/config/application.rb b/config/application.rb index ab94605..f9b478d 100644 --- a/config/application.rb +++ b/config/application.rb @@ -28,6 +28,8 @@ module Railsondocker # Common ones are `templates`, `generators`, or `middleware`, for example. config.autoload_lib(ignore: %w[assets tasks]) + config.autoload_paths += %W(#{config.root}/app/form_builders) + # Configuration for the application, engines, and railties goes here. # # These settings can be overridden in specific environments using the files diff --git a/config/database.yml b/config/database.yml index dab5735..162734a 100644 --- a/config/database.yml +++ b/config/database.yml @@ -13,16 +13,30 @@ # gem "pg" # default: &default - adapter: postgresql - encoding: unicode + adapter: sqlserver + mode: dblib # For details on connection pooling, see Rails configuration guide # https://guides.rubyonrails.org/configuring.html#database-pooling pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> development: - <<: *default - database: railsondocker_development + dev_tools: + <<: *default + host: db + database: dev_tools_dev + username: sa + password: Br1tt0nPassw0rd + vhcs: + <<: *default + # host: 10.41.82.72 #Prod + host: 10.41.82.73 #Dev + port: 1433 + database: VHCS_HIPAA + username: BSTI + password: BSTIBOY + database_tasks: false + tds_version: 7.3 # The specified database role being used to connect to PostgreSQL. # To create additional roles in PostgreSQL see `$ createuser --help`. @@ -54,9 +68,9 @@ development: # Warning: The database defined as "test" will be erased and # re-generated from your development database when you run "rake". # Do not set this db to the same as development or production. -test: - <<: *default - database: railsondocker_test +# test: +# <<: *default +# database: railsondocker_test # As with config/credentials.yml, you never want to store sensitive information, # like your database password, in your source code. If your source code is @@ -78,6 +92,6 @@ test: # Read https://guides.rubyonrails.org/configuring.html#configuring-a-database # for a full overview on how database connection configuration can be specified. # -production: - <<: *default - url: <%= ENV['DATABASE_URL'] %> +# production: +# <<: *default +# url: <%= ENV['DATABASE_URL'] %> diff --git a/config/environments/development.rb b/config/environments/development.rb index 935688c..b8d969a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -44,7 +44,7 @@ Rails.application.configure do # caching is enabled. config.action_mailer.perform_caching = false - config.action_mailer.default_url_options = { host: "localhost", port: 3000 } + config.action_mailer.default_url_options = { host: "localhost", port: 3002 } # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/config/initializers/action_view.rb b/config/initializers/action_view.rb new file mode 100644 index 0000000..81dd9fa --- /dev/null +++ b/config/initializers/action_view.rb @@ -0,0 +1,4 @@ +# config/initializers/action_view.rb +Rails.application.config.to_prepare do + ActionView::Base.default_form_builder = TailwindFormBuilder +end \ No newline at end of file diff --git a/config/puma.rb b/config/puma.rb index 60e1b9c..2620821 100644 --- a/config/puma.rb +++ b/config/puma.rb @@ -24,10 +24,12 @@ threads_count = ENV.fetch("RAILS_MAX_THREADS", 3) threads threads_count, threads_count # Specifies the `port` that Puma will listen on to receive requests; default is 3000. -port ENV.fetch("PORT", 3000) +port ENV.fetch("PORT", 3002) # Allow puma to be restarted by `bin/rails restart` command. plugin :tmp_restart +plugin :tailwindcss + # Only use a pidfile when requested pidfile ENV["PIDFILE"] if ENV["PIDFILE"] diff --git a/config/routes.rb b/config/routes.rb index 1a45f06..d0fa713 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true Rails.application.routes.draw do + resources :employer_setup, only: [:new, :create] get "welcome/index" # Reveal health status on /up that returns 200 if the app boots with no exceptions, otherwise 500. diff --git a/db/migrate/20210926221100_create_articles.rb b/db/migrate/20210926221100_create_articles.rb deleted file mode 100644 index c802e5f..0000000 --- a/db/migrate/20210926221100_create_articles.rb +++ /dev/null @@ -1,10 +0,0 @@ -class CreateArticles < ActiveRecord::Migration[7.0] - def change - create_table :articles do |t| - t.string :title - t.text :content - - t.timestamps - end - end -end diff --git a/db/migrate/20211216185503_create_comments.rb b/db/migrate/20211216185503_create_comments.rb deleted file mode 100644 index 0a9772a..0000000 --- a/db/migrate/20211216185503_create_comments.rb +++ /dev/null @@ -1,10 +0,0 @@ -class CreateComments < ActiveRecord::Migration[7.0] - def change - create_table :comments do |t| - t.references :article, null: false, foreign_key: true - t.text :content - - t.timestamps - end - end -end diff --git a/db/migrate/20251104171719_create_id_card_benefits_templates.rb b/db/migrate/20251104171719_create_id_card_benefits_templates.rb new file mode 100644 index 0000000..5d5bf6b --- /dev/null +++ b/db/migrate/20251104171719_create_id_card_benefits_templates.rb @@ -0,0 +1,9 @@ +class CreateIdCardBenefitsTemplates < ActiveRecord::Migration[7.2] + def change + create_table :id_card_benefits_templates do |t| + t.string :title + + t.timestamps + end + end +end diff --git a/db/migrate/20251104171752_create_id_card_benefits.rb b/db/migrate/20251104171752_create_id_card_benefits.rb new file mode 100644 index 0000000..1f98816 --- /dev/null +++ b/db/migrate/20251104171752_create_id_card_benefits.rb @@ -0,0 +1,12 @@ +class CreateIdCardBenefits < ActiveRecord::Migration[7.2] + def change + create_table :id_card_benefits do |t| + t.string :benefit_desc + t.string :benefit + t.integer :sequence + t.references :id_card_benefits_template, null: false, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index a2cf224..3abb0ba 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,10 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.1].define(version: 2023_03_26_154219) do - # These are extensions that must be enabled in order to support this database - enable_extension "plpgsql" - +ActiveRecord::Schema[7.2].define(version: 2025_11_04_171752) do create_table "action_text_rich_texts", force: :cascade do |t| t.string "name", null: false t.text "body" @@ -52,22 +49,23 @@ ActiveRecord::Schema[7.1].define(version: 2023_03_26_154219) do t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true end - create_table "articles", force: :cascade do |t| - t.string "title" - t.text "content" + create_table "id_card_benefits", force: :cascade do |t| + t.string "benefit_desc" + t.string "benefit" + t.integer "sequence" + t.bigint "id_card_benefits_template_id", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.index ["id_card_benefits_template_id"], name: "index_id_card_benefits_on_id_card_benefits_template_id" end - create_table "comments", force: :cascade do |t| - t.bigint "article_id", null: false - t.text "content" + create_table "id_card_benefits_templates", force: :cascade do |t| + t.string "title" t.datetime "created_at", null: false t.datetime "updated_at", null: false - t.index ["article_id"], name: "index_comments_on_article_id" end 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 "comments", "articles" + add_foreign_key "id_card_benefits", "id_card_benefits_templates" end diff --git a/db/seeds.rb b/db/seeds.rb index 0f16211..35e1b10 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -9,3 +9,12 @@ # ["Action", "Comedy", "Drama", "Horror"].each do |genre_name| # MovieGenre.find_or_create_by!(name: genre_name) # end + +# Pull one planid, return data, run this +# data.each do |bene| +# IdCardBenefit.create( +# benefit_desc: bene.benefit_desc, +# sequence: bene.sequence, +# id_card_benefits_template: temp +# ) +# end \ No newline at end of file diff --git a/development.Dockerfile b/development.Dockerfile index 824c998..3c35479 100644 --- a/development.Dockerfile +++ b/development.Dockerfile @@ -13,16 +13,71 @@ RUN --mount=type=cache,target=/var/cache/apt \ apt-get update -qq \ && apt-get install -yq --no-install-recommends \ build-essential \ + cmake \ + ruby-dev \ gnupg2 \ less \ git \ - libpq-dev \ - postgresql-client \ + unixodbc \ + unixodbc-dev \ + tdsodbc \ + freetds-dev \ libvips \ + libpq-dev \ curl \ libjemalloc2 \ pkg-config \ - libyaml-dev + python3-dev \ + wget \ + libtool \ + libssl-dev && \ + rm -rf /var/lib/apt/lists/* + +ARG WATCHMAN_VERSION=v2025.11.10.00 +WORKDIR /tmp +RUN git clone https://github.com/facebook/watchman.git -b ${WATCHMAN_VERSION} --depth 1 && \ + cd watchman && \ + ./autogen.sh && \ + ./configure && \ + make && \ + make install + +# Download and install Watchman from the pre-compiled binary +# RUN curl -L https://github.com/facebook/watchman/archive/refs/tags/v${WATCHMAN_VERSION}.zip -o watchman.zip \ +# && unzip watchman.zip \ +# && rm watchman.zip \ +# && cd watchman-${WATCHMAN_VERSION} \ +# && mkdir -p /usr/local/{bin,lib} /usr/local/var/run/watchman \ +# && chmod 755 /usr/local/bin/watchman \ +# && chmod 2777 /usr/local/var/run/watchman \ +# && cd .. \ +# && rm -fr ${WATCHMAN_VERSION} + +# OS Level Dependencies +# RUN --mount=type=cache,target=/var/cache/apt \ +# --mount=type=cache,target=/var/lib/apt,sharing=locked \ +# --mount=type=tmpfs,target=/var/log \ +# rm -f /etc/apt/apt.conf.d/docker-clean; \ +# echo 'Binary::apt::APT::Keep-Downloaded-Packages "true";' > /etc/apt/apt.conf.d/keep-cache; \ +# apt-get update -qq \ +# && apt-get install -yq --no-install-recommends \ +# build-essential \ +# ruby-dev \ +# gnupg2 \ +# less \ +# git \ +# unixodbc \ +# unixodbc-dev \ +# tdsodbc \ +# freetds-dev \ +# libvips \ +# libpq-dev \ +# curl \ +# libjemalloc2 \ +# pkg-config \ +# libtool \ +# libssl-dev && \ +# rm -rf /var/lib/apt/lists/* ENV LANG=C.UTF-8 \ BUNDLE_JOBS=4 \ @@ -32,6 +87,6 @@ WORKDIR /usr/src/app ENTRYPOINT ["./bin/docker-entrypoint-development"] -EXPOSE 3000 +EXPOSE 3002 CMD ["./bin/rails", "server"] diff --git a/development2.Dockerfile b/development2.Dockerfile new file mode 100644 index 0000000..8f3ea7e --- /dev/null +++ b/development2.Dockerfile @@ -0,0 +1,73 @@ +# ----- Build Stage ----- +# Using a specific Ruby version (e.g., 3.3) for stability +ARG RUBY_VERSION=3.3.9 +FROM ruby:$RUBY_VERSION as builder + +# Install system dependencies needed for Ruby gems and asset building +RUN apt-get update -qq && apt-get install -y \ + build-essential \ + libpq-dev \ + libvips \ + nodejs \ + npm \ + git \ + curl \ + watchman \ + && rm -rf /var/lib/apt/lists/* \ + # For TailwindCSS, install the npm package instead of relying on the system executable + # as there have been issues with architecture mismatches in containers + && npm install -g tailwindcss + +# Set the working directory inside the container +WORKDIR /usr/src/app + +# Copy and install Ruby dependencies +COPY Gemfile Gemfile.lock ./ +RUN bundle install + +# Copy the rest of the application code +COPY . . + +# Precompile assets for production using the installed Tailwind CLI +# This uses the installed 'tailwindcss' executable rather than the gem's wrapper +# RUN bundle exec rails assets:precompile + +# ----- Production Stage ----- +# Use a smaller Ruby image for the final production build +FROM ruby:$RUBY_VERSION-slim + +# Install production system dependencies +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=tmpfs,target=/var/log \ + rm -f /etc/apt/apt.conf.d/docker-clean; \ + apt-get update -qq \ + && apt-get install -yq --no-install-recommends \ + build-essential \ + less \ + git \ + tdsodbc \ + freetds-dev \ + libvips \ + libpq-dev + +ENV LANG=C.UTF-8 \ + BUNDLE_JOBS=4 \ + BUNDLE_RETRY=3 + +WORKDIR /usr/src/app + +# Copy runtime Ruby dependencies and the precompiled assets from the builder stage +COPY --from=builder /usr/local/bundle /usr/local/bundle +COPY --from=builder /usr/src/app /usr/src/app +COPY --from=builder /usr/local/bin/watchman /usr/local/bin/watchman +COPY --from=builder /usr/local/bin/watchman-wait /usr/local/bin/watchman-wai + +# The entrypoint script is a good practice for handling Rails server startup +ENTRYPOINT ["./bin/docker-entrypoint-development"] + +# Expose the application port +EXPOSE 3002 + +# Set the default command to run the Rails server +CMD ["./bin/rails", "server"] diff --git a/development3.Dockerfile b/development3.Dockerfile new file mode 100644 index 0000000..126de58 --- /dev/null +++ b/development3.Dockerfile @@ -0,0 +1,46 @@ +# ----- Build Stage ----- +# Using a specific Ruby version (e.g., 3.3) for stability +ARG RUBY_VERSION=3.3.9 +FROM docker.io/library/ruby:$RUBY_VERSION-slim as base + +# Install production system dependencies +RUN --mount=type=cache,target=/var/cache/apt \ + --mount=type=cache,target=/var/lib/apt,sharing=locked \ + --mount=type=tmpfs,target=/var/log \ + rm -f /etc/apt/apt.conf.d/docker-clean; \ + apt-get update -qq \ + && apt-get install -yq --no-install-recommends \ + build-essential \ + less \ + git \ + tdsodbc \ + freetds-dev \ + libvips \ + libpq-dev + +ENV LANG=C.UTF-8 \ + BUNDLE_JOBS=4 \ + BUNDLE_RETRY=3 + +WORKDIR /usr/src/app + +RUN gem install foreman + +# Copy runtime Ruby dependencies and the precompiled assets from the builder stage +# COPY --from=builder /usr/local/bundle /usr/local/bundle +# COPY --from=builder /usr/src/app /usr/src/app +# COPY --from=watchman_builder /usr/local/bin/watchman /usr/local/bin/watchman +# COPY --from=watchman_builder /usr/local/bin/watchman-wait /usr/local/bin/watchman-wait + +# RUN mkdir -p /usr/local/var/run/watchman \ +# && touch /usr/local/var/run/watchman/.not-empty \ +# && chmod 2777 /usr/local/var/run/watchman + +# The entrypoint script is a good practice for handling Rails server startup +ENTRYPOINT ["./bin/docker-entrypoint-development"] + +# Expose the application port +EXPOSE 3002 + +# Set the default command to run the Rails server +CMD ["./bin/dev"] diff --git a/init.sql b/init.sql new file mode 100644 index 0000000..9bfa0d9 --- /dev/null +++ b/init.sql @@ -0,0 +1,5 @@ +IF NOT EXISTS (SELECT name FROM master.dbo.sysdatabases WHERE name = N'britton_dev_tools_dev') +BEGIN + CREATE DATABASE [britton_dev_tools_dev]; + CREATE DATABASE [britton_dev_tools_test]; +END; \ No newline at end of file diff --git a/lib/generators/legacy_db_model/USAGE b/lib/generators/legacy_db_model/USAGE new file mode 100644 index 0000000..6857db4 --- /dev/null +++ b/lib/generators/legacy_db_model/USAGE @@ -0,0 +1,8 @@ +Description: + Explain the generator + +Example: + bin/rails generate legacy_db_model Thing + + This will create: + what/will/it/create diff --git a/lib/generators/legacy_db_model/legacy_db_model_generator.rb b/lib/generators/legacy_db_model/legacy_db_model_generator.rb new file mode 100644 index 0000000..84d8d19 --- /dev/null +++ b/lib/generators/legacy_db_model/legacy_db_model_generator.rb @@ -0,0 +1,79 @@ +class LegacyDbModelGenerator < Rails::Generators::Base + source_root File.expand_path('templates', __dir__) + + argument :db_name, type: :string, required: true + argument :table_name, type: :string, required: true + + def determine_db_record + if db_name == 'VHCS_HIPAA' + @db_record = 'VhcsRecord'.constantize + @module = 'Vhcs'.constantize + @file_folder = 'vhcs' + elsif db_name == 'HEBWeb' + @db_record = 'WebRecord'.constantize + @module = 'HebWeb'.constantize + @file_folder = 'heb_web' + else + raise LegacyDBModelError, "Invalid database, please use VHCS_HIPAA or HEBWeb" + end + end + + def get_fields_if_table_exists + tn = table_name.strip + if @db_record.connection.table_exists?(tn) || @db_record.connection.view_exists?(table_name) + @fields = @db_record.connection.columns(tn).map { |col| col.name } + else + raise LegacyDBModelError, "Invalid table/view for #{db_name}, please double check spelling and capitalization" + end + end + + + # Add argurment for database, depending on db - change AR::Base below to correct db record + # Find out way to error out if table not found + + + # use this code to get table field names here, convert to underscore, + # send as aray or array pairs, and pass to template. + # columns = ActiveRecord::Base.connection.columns(table_name) + # field_names = columns.map(&:name) + + def create_model_file + template "legacy_model.rb.erb.tt", "app/models/#{@file_folder}/#{file_name}.rb" + end + + # kick off another schema dump and rebuild alt db schema + # Will need to persist what tables to run (maybe in db, maybe in alt db schema) + + private + + def file_name + "#{table_name.underscore}" + end + + def class_name + "#{table_name.camelize}" + end + + def uddt_type_mapping + { + "uddtBaseKey" => "integer, limit: 8", + "uddtIdPlan" => "string", + "uddtBaseEnum" => "uddt_base_enum", + "uddtBaseShortDesc" => "string", + "uddtBaseLongDesc" => "string", + "uddtBaseContact" => "string", + "uddtAddrCity" => "string", + "uddtAddrState" => "string", + "uddtAddrStreet" => "string", + "uddtAddrZip" => "string", + "uddtContPhone" => "string", + "uddtIdTax" => "string", + "uddtNotesNote" => "string", + "uddtFooter" => "string", + "uddtBaseDate" => "datetime", + "uddtBaseUserId" => "string" + } + end + + class LegacyDBModelError < StandardError; end +end diff --git a/lib/generators/legacy_db_model/templates/legacy_model.rb.erb.tt b/lib/generators/legacy_db_model/templates/legacy_model.rb.erb.tt new file mode 100644 index 0000000..2e51266 --- /dev/null +++ b/lib/generators/legacy_db_model/templates/legacy_model.rb.erb.tt @@ -0,0 +1,12 @@ +module <%= @module %> + class <%= class_name %> < <%= @db_record %> + + self.table_name = '<%= table_name %>' + + <%- @fields.each do |fi| -%> + alias_attribute :<%= fi.underscore %>, :<%= fi %> + <%- end -%> + + + end +end \ No newline at end of file diff --git a/scratch.rb b/scratch.rb new file mode 100644 index 0000000..e69de29