From 5a90ea6e140147380d5eaf8fc0d7ad214955ed98 Mon Sep 17 00:00:00 2001 From: Jason Jordan Date: Wed, 17 Jun 2026 23:23:36 -0400 Subject: [PATCH] beta build --- Dockerfile | 9 ++- Gemfile.lock | 2 + app/controllers/brokers_controller.rb | 70 +++++++++++++++++++ app/controllers/carriers_controller.rb | 70 +++++++++++++++++++ app/controllers/employers_controller.rb | 4 +- app/controllers/id_card/print_controller.rb | 15 ++++ app/controllers/provider_groups_controller.rb | 70 +++++++++++++++++++ app/controllers/providers_controller.rb | 70 +++++++++++++++++++ app/helpers/brokers_helper.rb | 2 + app/helpers/carriers_helper.rb | 2 + app/helpers/provider_groups_helper.rb | 2 + app/helpers/providers_helper.rb | 2 + app/javascript/application.js | 17 ++--- app/javascript/controllers/index.js | 9 +-- app/jobs/process_member_card_data_job.rb | 14 ++-- app/jobs/update_member_job.rb | 10 ++- app/models/broker.rb | 4 ++ app/models/carrier.rb | 3 + app/models/employer.rb | 8 +++ app/models/heb_web/broker_x_ref.rb | 14 ++++ app/models/heb_web_record.rb | 4 ++ app/models/id_card/plan.rb | 1 + app/models/member.rb | 5 +- app/models/provider.rb | 2 + app/models/provider_group.rb | 2 + .../automation_service/member_update.rb | 2 +- .../beta_automation_simulation_service.rb | 7 +- app/services/image_processor_service.rb | 33 +++++++++ bin/importmap | 0 config/application.rb | 4 +- config/database.yml | 61 +++++++++++++++- config/environments/development.rb | 5 +- config/environments/production.rb | 3 +- config/importmap.rb | 4 +- config/routes.rb | 4 ++ config/schedule.rb | 6 +- db/migrate/20260513154359_create_carriers.rb | 9 +++ db/migrate/20260513154436_create_brokers.rb | 10 +++ ...053_update_employer_to_belong_to_broker.rb | 5 ++ .../20260513162002_create_provider_groups.rb | 9 +++ db/migrate/20260513162029_create_providers.rb | 13 ++++ db/schema.rb | 38 +++++++++- db/seeds.rb | 2 +- docker-compose.yaml | 11 +-- .../legacy_db_model_generator.rb | 2 +- lib/tasks/employer_automation.rake | 12 +++- lib/tasks/seed_tasks.rake | 20 +++++- prod.docker-compose.yaml | 57 +++++++++++++++ 48 files changed, 674 insertions(+), 54 deletions(-) create mode 100644 app/controllers/brokers_controller.rb create mode 100644 app/controllers/carriers_controller.rb create mode 100644 app/controllers/provider_groups_controller.rb create mode 100644 app/controllers/providers_controller.rb create mode 100644 app/helpers/brokers_helper.rb create mode 100644 app/helpers/carriers_helper.rb create mode 100644 app/helpers/provider_groups_helper.rb create mode 100644 app/helpers/providers_helper.rb create mode 100644 app/models/broker.rb create mode 100644 app/models/carrier.rb create mode 100644 app/models/heb_web/broker_x_ref.rb create mode 100644 app/models/heb_web_record.rb create mode 100644 app/models/provider.rb create mode 100644 app/models/provider_group.rb create mode 100755 app/services/image_processor_service.rb mode change 100644 => 100755 bin/importmap create mode 100644 db/migrate/20260513154359_create_carriers.rb create mode 100644 db/migrate/20260513154436_create_brokers.rb create mode 100644 db/migrate/20260513155053_update_employer_to_belong_to_broker.rb create mode 100644 db/migrate/20260513162002_create_provider_groups.rb create mode 100644 db/migrate/20260513162029_create_providers.rb create mode 100644 prod.docker-compose.yaml diff --git a/Dockerfile b/Dockerfile index eb4c602..2a0241f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -50,17 +50,24 @@ RUN bundle install && \ # Copy application code COPY . . +RUN ./bin/rails stimulus:manifest:update +RUN ./bin/importmap pin . + # RUN bundle exec ./bin/rails rails_icons:sync RUN ./bin/rails generate rails_icons:sync --libraries=lucide # Precompile assets (Tailwind is triggered here via assets:precompile) # SECRET_KEY_BASE_DUMMY allows precompilation without real secrets -RUN SECRET_KEY_BASE_DUMMY=1 ./bin/rails assets:precompile +# RUN bundle exec rails assets:clobber assets:precompile RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 +RUN bundle exec rails assets:precompile RAILS_ENV=production SECRET_KEY_BASE_DUMMY=1 # 3. Final Stage: Lean Runtime FROM base # Copy built artifacts: gems and precompiled assets +# COPY --from=build /rails/public /rails/public +# COPY --from=build /rails/app/javascript /rails/app/javascript +# COPY --from=build /rails/config/importmap.rb /rails/config/importmap.rb COPY --from=build /usr/local/bundle /usr/local/bundle COPY --from=build /rails /rails diff --git a/Gemfile.lock b/Gemfile.lock index e386793..e902b80 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -117,6 +117,7 @@ GEM connection_pool (3.0.2) crass (1.0.6) csv (3.3.5) + daemons (1.4.1) date (3.5.1) delayed_job (4.2.0) activesupport (>= 3.0, < 9.0) @@ -422,6 +423,7 @@ DEPENDENCIES bundler-audit capybara combine_pdf + daemons delayed_job_active_record devise docx diff --git a/app/controllers/brokers_controller.rb b/app/controllers/brokers_controller.rb new file mode 100644 index 0000000..b9283fd --- /dev/null +++ b/app/controllers/brokers_controller.rb @@ -0,0 +1,70 @@ +class BrokersController < ApplicationController + before_action :set_broker, only: %i[ show edit update destroy ] + + # GET /brokers or /brokers.json + def index + @brokers = Broker.all + end + + # GET /brokers/1 or /brokers/1.json + def show + end + + # GET /brokers/new + def new + @broker = Broker.new + end + + # GET /brokers/1/edit + def edit + end + + # POST /brokers or /brokers.json + def create + @broker = Broker.new(broker_params) + + respond_to do |format| + if @broker.save + format.html { redirect_to @broker, notice: "Broker was successfully created." } + format.json { render :show, status: :created, location: @broker } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @broker.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /brokers/1 or /brokers/1.json + def update + respond_to do |format| + if @broker.update(broker_params) + format.html { redirect_to @broker, notice: "Broker was successfully updated.", status: :see_other } + format.json { render :show, status: :ok, location: @broker } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @broker.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /brokers/1 or /brokers/1.json + def destroy + @broker.destroy! + + respond_to do |format| + format.html { redirect_to brokers_path, notice: "Broker was successfully destroyed.", status: :see_other } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_broker + @broker = Broker.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def broker_params + params.require(:broker).permit(:name, :carrier_id) + end +end diff --git a/app/controllers/carriers_controller.rb b/app/controllers/carriers_controller.rb new file mode 100644 index 0000000..2711033 --- /dev/null +++ b/app/controllers/carriers_controller.rb @@ -0,0 +1,70 @@ +class CarriersController < ApplicationController + before_action :set_carrier, only: %i[ show edit update destroy ] + + # GET /carriers or /carriers.json + def index + @carriers = Carrier.all + end + + # GET /carriers/1 or /carriers/1.json + def show + end + + # GET /carriers/new + def new + @carrier = Carrier.new + end + + # GET /carriers/1/edit + def edit + end + + # POST /carriers or /carriers.json + def create + @carrier = Carrier.new(carrier_params) + + respond_to do |format| + if @carrier.save + format.html { redirect_to @carrier, notice: "Carrier was successfully created." } + format.json { render :show, status: :created, location: @carrier } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @carrier.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /carriers/1 or /carriers/1.json + def update + respond_to do |format| + if @carrier.update(carrier_params) + format.html { redirect_to @carrier, notice: "Carrier was successfully updated.", status: :see_other } + format.json { render :show, status: :ok, location: @carrier } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @carrier.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /carriers/1 or /carriers/1.json + def destroy + @carrier.destroy! + + respond_to do |format| + format.html { redirect_to carriers_path, notice: "Carrier was successfully destroyed.", status: :see_other } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_carrier + @carrier = Carrier.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def carrier_params + params.require(:carrier).permit(:name) + end +end diff --git a/app/controllers/employers_controller.rb b/app/controllers/employers_controller.rb index 1002af1..7aecdc0 100644 --- a/app/controllers/employers_controller.rb +++ b/app/controllers/employers_controller.rb @@ -3,9 +3,9 @@ class EmployersController < ApplicationController # View Methods def index @uninitialized = Employer.in_automation_initilization - @with_active_id_card_setup = Employer.with_active_id_card_setup + @with_active_id_card_setup = Employer.active current_group_numbers = @with_active_id_card_setup.pluck(:group_number) - valid_group_numbers = ["62210","61986","42018","41283","0230643","43190","0230642","0230644","0230646","0233955","600102","0249127","0257902","0257947","600112","0260085","600114","0261611","600117","0261684","0261685","0261826","600121","0265450","600123","0267470","0268540","0268599"] + valid_group_numbers = ["62210","61986","42018","41283","0230643","43190","0230642","0230644","0230646","0233955","600102","0249127","0257902","0257947","600112","600114","0261611","600117","0261684","0261685","0261826","600121","0265450","600123","0267470","0268540","0268599"] @beta_unassigned_group_numbers = valid_group_numbers - current_group_numbers @deactivated = Employer.deactivated end diff --git a/app/controllers/id_card/print_controller.rb b/app/controllers/id_card/print_controller.rb index d57aeaf..8e2cf52 100644 --- a/app/controllers/id_card/print_controller.rb +++ b/app/controllers/id_card/print_controller.rb @@ -5,6 +5,7 @@ module IdCard def index @employer_setups = IdCard::Setup.active.to_a @queue_members = IdCardQueueService::GetQueuedMembers.new().call + update_missing_members(@queue_members) add_queued_count_to_employer_setup(@queue_members) @queued = @employer_setups.select { |setup| setup.queued_card_count > 0 }.sort_by { |setup| setup.print_name } @not_queued = @employer_setups.select { |setup| setup.queued_card_count == 0 }.sort_by { |setup| setup.print_name } @@ -15,6 +16,9 @@ module IdCard def print_all_queued @queue_members = IdCardQueueService::GetQueuedMembers.new().call + # @queue_members.delete_if { |em| ["2", "19", "16", "54"].include?(em[:pl_plan_key])} + # @queue_members.push({pl_plan_key: "54", member_keys: [383840]}) + cards_pdf = IdCardPrinterService::CardsGenerator.new(@queue_members, "PrintCard").call send_data cards_pdf.to_pdf, @@ -28,6 +32,7 @@ module IdCard pl_plan_key = params[:id].to_s @employer = Employer.find_by(pl_plan_key: pl_plan_key) @queue_members = IdCardQueueService::GetQueuedMembers.new(pl_plan_key).call + # @queue_members.first[:member_keys].delete(379590) && @queue_members.first[:member_keys].push(379610) cards_pdf = IdCardPrinterService::CardsGenerator.new(@queue_members, "PrintCard").call send_data cards_pdf.to_pdf, @@ -103,6 +108,16 @@ module IdCard end private + + def update_missing_members(queued_employer_members) + queued_employer_members.each do |queued_employer| + existing_members = Member.where(pb_entity_key: queued_employer[:member_keys]).pluck(:pb_entity_key) + missing_members = queued_employer[:member_keys] - existing_members + missing_members.each do |pb_entity_key| + AutomationService::MemberUpdate.new(queued_employer[:pl_plan_key], pb_entity_key).call + end + end + end def add_queued_count_to_employer_setup(queued_employer_members) diff --git a/app/controllers/provider_groups_controller.rb b/app/controllers/provider_groups_controller.rb new file mode 100644 index 0000000..b4a6b1e --- /dev/null +++ b/app/controllers/provider_groups_controller.rb @@ -0,0 +1,70 @@ +class ProviderGroupsController < ApplicationController + before_action :set_provider_group, only: %i[ show edit update destroy ] + + # GET /provider_groups or /provider_groups.json + def index + @provider_groups = ProviderGroup.all + end + + # GET /provider_groups/1 or /provider_groups/1.json + def show + end + + # GET /provider_groups/new + def new + @provider_group = ProviderGroup.new + end + + # GET /provider_groups/1/edit + def edit + end + + # POST /provider_groups or /provider_groups.json + def create + @provider_group = ProviderGroup.new(provider_group_params) + + respond_to do |format| + if @provider_group.save + format.html { redirect_to @provider_group, notice: "Provider group was successfully created." } + format.json { render :show, status: :created, location: @provider_group } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @provider_group.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /provider_groups/1 or /provider_groups/1.json + def update + respond_to do |format| + if @provider_group.update(provider_group_params) + format.html { redirect_to @provider_group, notice: "Provider group was successfully updated.", status: :see_other } + format.json { render :show, status: :ok, location: @provider_group } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @provider_group.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /provider_groups/1 or /provider_groups/1.json + def destroy + @provider_group.destroy! + + respond_to do |format| + format.html { redirect_to provider_groups_path, notice: "Provider group was successfully destroyed.", status: :see_other } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_provider_group + @provider_group = ProviderGroup.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def provider_group_params + params.require(:provider_group).permit(:name) + end +end diff --git a/app/controllers/providers_controller.rb b/app/controllers/providers_controller.rb new file mode 100644 index 0000000..ee19ae5 --- /dev/null +++ b/app/controllers/providers_controller.rb @@ -0,0 +1,70 @@ +class ProvidersController < ApplicationController + before_action :set_provider, only: %i[ show edit update destroy ] + + # GET /providers or /providers.json + def index + @providers = Provider.all + end + + # GET /providers/1 or /providers/1.json + def show + end + + # GET /providers/new + def new + @provider = Provider.new + end + + # GET /providers/1/edit + def edit + end + + # POST /providers or /providers.json + def create + @provider = Provider.new(provider_params) + + respond_to do |format| + if @provider.save + format.html { redirect_to @provider, notice: "Provider was successfully created." } + format.json { render :show, status: :created, location: @provider } + else + format.html { render :new, status: :unprocessable_entity } + format.json { render json: @provider.errors, status: :unprocessable_entity } + end + end + end + + # PATCH/PUT /providers/1 or /providers/1.json + def update + respond_to do |format| + if @provider.update(provider_params) + format.html { redirect_to @provider, notice: "Provider was successfully updated.", status: :see_other } + format.json { render :show, status: :ok, location: @provider } + else + format.html { render :edit, status: :unprocessable_entity } + format.json { render json: @provider.errors, status: :unprocessable_entity } + end + end + end + + # DELETE /providers/1 or /providers/1.json + def destroy + @provider.destroy! + + respond_to do |format| + format.html { redirect_to providers_path, notice: "Provider was successfully destroyed.", status: :see_other } + format.json { head :no_content } + end + end + + private + # Use callbacks to share common setup or constraints between actions. + def set_provider + @provider = Provider.find(params[:id]) + end + + # Only allow a list of trusted parameters through. + def provider_params + params.fetch(:provider, {}) + end +end diff --git a/app/helpers/brokers_helper.rb b/app/helpers/brokers_helper.rb new file mode 100644 index 0000000..6e6ed1a --- /dev/null +++ b/app/helpers/brokers_helper.rb @@ -0,0 +1,2 @@ +module BrokersHelper +end diff --git a/app/helpers/carriers_helper.rb b/app/helpers/carriers_helper.rb new file mode 100644 index 0000000..672e928 --- /dev/null +++ b/app/helpers/carriers_helper.rb @@ -0,0 +1,2 @@ +module CarriersHelper +end diff --git a/app/helpers/provider_groups_helper.rb b/app/helpers/provider_groups_helper.rb new file mode 100644 index 0000000..e4b9587 --- /dev/null +++ b/app/helpers/provider_groups_helper.rb @@ -0,0 +1,2 @@ +module ProviderGroupsHelper +end diff --git a/app/helpers/providers_helper.rb b/app/helpers/providers_helper.rb new file mode 100644 index 0000000..b2e719d --- /dev/null +++ b/app/helpers/providers_helper.rb @@ -0,0 +1,2 @@ +module ProvidersHelper +end diff --git a/app/javascript/application.js b/app/javascript/application.js index 42bd8f2..f6cb4bf 100644 --- a/app/javascript/application.js +++ b/app/javascript/application.js @@ -2,14 +2,15 @@ import "@hotwired/turbo-rails" import "trix" import "@rails/actiontext" -import { Application } from "@hotwired/stimulus" -import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" -import { createIcons, icons } from "lucide-static"; +// import { Application } from "@hotwired/stimulus" +// import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" +import "controllers" +// import { createIcons, icons } from "lucide-static"; -document.addEventListener("turbo:load", () => { - createIcons({ icons }); -}); +// document.addEventListener("turbo:load", () => { +// createIcons({ icons }); +// }); -const application = Application.start() -eagerLoadControllersFrom("controllers", application) +// const application = Application.start() +// eagerLoadControllersFrom("controllers", application) diff --git a/app/javascript/controllers/index.js b/app/javascript/controllers/index.js index 54ad4ca..84118d3 100644 --- a/app/javascript/controllers/index.js +++ b/app/javascript/controllers/index.js @@ -1,11 +1,8 @@ -// Import and register all your controllers from the importmap under controllers/* - +// This file is auto-generated by ./bin/rails stimulus:manifest:update +// Run that command whenever you add a new controller or create them with +// ./bin/rails generate stimulus controllerName import { application } from "controllers/application" // Eager load all controllers defined in the import map under controllers/**/*_controller import { eagerLoadControllersFrom } from "@hotwired/stimulus-loading" eagerLoadControllersFrom("controllers", application) - -// Lazy load controllers as they appear in the DOM (remember not to preload controllers in import map!) -// import { lazyLoadControllersFrom } from "@hotwired/stimulus-loading" -// lazyLoadControllersFrom("controllers", application) diff --git a/app/jobs/process_member_card_data_job.rb b/app/jobs/process_member_card_data_job.rb index 7786a6d..5ef1bf7 100644 --- a/app/jobs/process_member_card_data_job.rb +++ b/app/jobs/process_member_card_data_job.rb @@ -56,14 +56,12 @@ class ProcessMemberCardDataJob < ApplicationJob end if has_dental - if member.dental_plan_key - member_attributes.merge!({dental_coverage: member.coverage_class.upcase}) - unless member.id_card_plan_id - member_attributes.merge!({group_number: "", medical_eff_date: ""}) - # dental_plan = IdCard::Plan.find_by(pb_product_key: 1025) - if IdCard::Plan.find_by(pb_product_key: member.dental_plan_key).blank? - member_attributes.merge!({employer_name: 'COBRA'}) - end + member_attributes.merge!({dental_coverage: member.coverage_class.upcase}) + if member.dental_plan_key && member.id_card_plan_id.blank? + member_attributes.merge!({group_number: "", medical_eff_date: ""}) + # dental_plan = IdCard::Plan.find_by(pb_product_key: 1025) + if IdCard::Plan.find_by(pb_product_key: member.dental_plan_key).blank? + member_attributes.merge!({employer_name: 'COBRA'}) end end end diff --git a/app/jobs/update_member_job.rb b/app/jobs/update_member_job.rb index 63ac4d6..72dc3ce 100644 --- a/app/jobs/update_member_job.rb +++ b/app/jobs/update_member_job.rb @@ -15,7 +15,7 @@ class UpdateMemberJob < ApplicationJob "PBCoveredEntities"."PBEntityKey" = ? AND "PBProductParticipation"."InEffect" <= ? AND "PBProductParticipation"."OutOfEffect" > ?', - vw_mb_member[:pb_entity_key], 2.month.from_now , 1.day.ago + vw_mb_member[:pb_entity_key], 3.month.from_now , 1.day.ago ) if pb_products.present? && vw_mb_member[:social_security_number].present? @@ -53,14 +53,18 @@ class UpdateMemberJob < ApplicationJob INNER JOIN "PBCoveredEntities" ON "PBProductParticipation"."PBProductParticipationKey" = "PBCoveredEntities"."PBProductParticipationKey" INNER JOIN "PBProductAvailability" ON "PBProductAvailability"."PBProductAvailabilityKey" = "PBProductParticipation"."PBProductAvailabilityKey" INNER JOIN "PBProduct" ON "PBProduct"."PBProductKey" = "PBProductAvailability"."PBProductKey" - ').find_by(' + ').select(' + "GEN_LookupTables".*, "PBProductParticipation"."InEffect" AS EffDate + ').where(' "PBCoveredEntities"."PBEntityKey" = ? AND "PBProductParticipation"."InEffect" <= ? AND "PBProductParticipation"."OutOfEffect" > ? AND "PBProduct"."PBProductKey" = ?', member.pb_entity_key, 1.month.from_now, 1.day.ago, dental_pb_product_key - ).short_desc + ).order('EffDate DESC').first.short_desc member.coverage_class = coverage_class + else + member.coverage_class = "NONE" end else medical_pb_product_key = pb_products.first.pb_product_key diff --git a/app/models/broker.rb b/app/models/broker.rb new file mode 100644 index 0000000..3416574 --- /dev/null +++ b/app/models/broker.rb @@ -0,0 +1,4 @@ +class Broker < ApplicationRecord + belongs_to :carrier + has_many :employers +end diff --git a/app/models/carrier.rb b/app/models/carrier.rb new file mode 100644 index 0000000..cc0306e --- /dev/null +++ b/app/models/carrier.rb @@ -0,0 +1,3 @@ +class Carrier < ApplicationRecord + has_many :brokers +end diff --git a/app/models/employer.rb b/app/models/employer.rb index cecade6..f133fb7 100644 --- a/app/models/employer.rb +++ b/app/models/employer.rb @@ -1,5 +1,6 @@ class Employer < ApplicationRecord include EmployerAutomation + belongs_to :broker, optional: true has_many :members, dependent: :destroy accepts_nested_attributes_for :members, allow_destroy: true, reject_if: :all_blank has_one :id_card_setup, class_name: 'IdCard::Setup', dependent: :destroy @@ -46,6 +47,13 @@ class Employer < ApplicationRecord } end + def employer_member_keys_by_plan(pb_product_key) + { + pl_plan_key: self.pl_plan_key, + member_keys: self.plans.find_by(pb_product_key: pb_product_key).members.pluck(:pb_entity_key) + } + end + def name_to_logo_filename(extension) Employer.employer_trim_name(self.name).titleize.gsub(/[^a-zA-Z]/, '').concat('Logo').concat(extension.downcase) end diff --git a/app/models/heb_web/broker_x_ref.rb b/app/models/heb_web/broker_x_ref.rb new file mode 100644 index 0000000..0203f76 --- /dev/null +++ b/app/models/heb_web/broker_x_ref.rb @@ -0,0 +1,14 @@ +module HebWeb + class BrokerXRef < HebWebRecord + + self.table_name = 'BrokerXRef' + + alias_attribute :id, :Id + alias_attribute :pl_plan_key, :PLPlanKey + alias_attribute :pb_entity_key, :PBEntityKey + alias_attribute :plan_name, :PlanName + alias_attribute :employer_pl_plan_key, :EmployerPLPlanKey + + + end +end diff --git a/app/models/heb_web_record.rb b/app/models/heb_web_record.rb new file mode 100644 index 0000000..ecb81e2 --- /dev/null +++ b/app/models/heb_web_record.rb @@ -0,0 +1,4 @@ +class HebWebRecord < ActiveRecord::Base + self.abstract_class = true + connects_to database: { writing: :heb_web, reading: :heb_web } +end diff --git a/app/models/id_card/plan.rb b/app/models/id_card/plan.rb index 32358aa..f4ab400 100644 --- a/app/models/id_card/plan.rb +++ b/app/models/id_card/plan.rb @@ -3,6 +3,7 @@ module IdCard belongs_to :setup, optional: true has_many :plan_benefits, dependent: :destroy accepts_nested_attributes_for :plan_benefits, allow_destroy: true, reject_if: :all_blank + has_many :members, class_name: 'Member', foreign_key: :id_card_plan_id validates :title, presence: true validates :pb_product_key, :pl_plan_key, presence: true, if: -> { setup&.active } diff --git a/app/models/member.rb b/app/models/member.rb index ec1e352..3e48f7a 100644 --- a/app/models/member.rb +++ b/app/models/member.rb @@ -9,8 +9,9 @@ class Member < ApplicationRecord validates :name, :family_id, :mb_member_key, :pl_plan_key, :id_card_display_name, presence: true, unless: :new_record? validates :division, presence: true, if: -> { employer.id_card_setup.has_divisions } - validates :coverage_class, :dental_plan_key, presence: true, if: -> { employer.id_card_setup.has_dental } - validates :name, :mb_member_key, :pb_entity_key, uniqueness: true + # validates :coverage_class, :dental_plan_key, presence: true, if: -> { employer.id_card_setup.has_dental } + validates :mb_member_key, :pb_entity_key, uniqueness: true + validates :name, uniqueness: { scope: :employer_id } before_validation :format_dependents, if: :dependents_changed? diff --git a/app/models/provider.rb b/app/models/provider.rb new file mode 100644 index 0000000..a929e51 --- /dev/null +++ b/app/models/provider.rb @@ -0,0 +1,2 @@ +class Provider < ApplicationRecord +end diff --git a/app/models/provider_group.rb b/app/models/provider_group.rb new file mode 100644 index 0000000..9092101 --- /dev/null +++ b/app/models/provider_group.rb @@ -0,0 +1,2 @@ +class ProviderGroup < ApplicationRecord +end diff --git a/app/services/automation_service/member_update.rb b/app/services/automation_service/member_update.rb index 3f4c5e0..5bf4de8 100644 --- a/app/services/automation_service/member_update.rb +++ b/app/services/automation_service/member_update.rb @@ -13,7 +13,7 @@ module AutomationService if member.present? member.save else - Member.find_by(pb_entity_key: vw_mb_member[:pb_entity_key]).destroy + Member.find_by(pb_entity_key: @pb_entity_key).destroy end end diff --git a/app/services/beta_automation_simulation_service.rb b/app/services/beta_automation_simulation_service.rb index bc30602..f42cc6a 100644 --- a/app/services/beta_automation_simulation_service.rb +++ b/app/services/beta_automation_simulation_service.rb @@ -1,8 +1,13 @@ +require 'rake' + class BetaAutomationSimulationService def initialize() end def call - Rails::Command.invoke('employer_automation:employer_initialize_test') + # Rails::Command.invoke('employer_automation:employer_initialize_test') + + Rails.application.load_tasks + Rake::Task['employer_automation:employer_initialize_test'].invoke end end \ No newline at end of file diff --git a/app/services/image_processor_service.rb b/app/services/image_processor_service.rb new file mode 100755 index 0000000..3506114 --- /dev/null +++ b/app/services/image_processor_service.rb @@ -0,0 +1,33 @@ +class ImageProcessorService + ALLOWED_LOGO_TYPES = ['Network', 'Employer'].freeze + + def initialize(image_path, logo_type, new_filename = nil) + @image_path = image_path + @logo_type = logo_type.capitalize + @new_filename = new_filename + + unless ALLOWED_LOGO_TYPES.include?(@logo_type) + raise ArgumentError, "Invalid logo type: #{@logo_type}. Must be one of: #{ALLOWED_LOGO_TYPES.join(', ')}" + end + end + + def call + + if @new_filename + filename = @new_filename + else + filename = File.basename(@image_path) + end + + binary_data = File.binread(@image_path) + # binary_data = File.open(@image_path, 'rb').read + meme_type = Marcel::MimeType.for Pathname.new(@image_path) + + logo_model = "IdCard::#{@logo_type}Logo".constantize + + logo_model.find_or_create_by(filename: filename) do |logo| + logo.image_data = binary_data + logo.content_type = meme_type + end + end +end \ No newline at end of file diff --git a/bin/importmap b/bin/importmap old mode 100644 new mode 100755 diff --git a/config/application.rb b/config/application.rb index addd03c..bcec6e7 100644 --- a/config/application.rb +++ b/config/application.rb @@ -40,8 +40,8 @@ module Baclight # Don't generate system test files. config.generators.system_tests = nil - # config.active_job.queue_adapter = :delayed_job - config.active_job.queue_adapter = :solid_queue + config.active_job.queue_adapter = :delayed_job + # config.active_job.queue_adapter = :solid_queue config.autoload_lib(ignore: %w[generators]) end diff --git a/config/database.yml b/config/database.yml index a536026..03a17bc 100644 --- a/config/database.yml +++ b/config/database.yml @@ -16,6 +16,54 @@ production: mode: dblib pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + host: "10.41.82.73" + port: 1433 + database: VHCS_HIPAA + username: BSTI + password: BSTIBOY + database_tasks: false + tds_version: 7.3 + britton_web: + adapter: sqlserver + mode: dblib + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + + host: 10.41.82.73 + port: 1433 + database: BrittonWeb + username: BSTI + password: BSTIBOY + database_tasks: false + tds_version: 7.3 + heb_web: + adapter: sqlserver + mode: dblib + host: 10.41.82.73 + port: 1433 + database: HEBWeb + username: SA + password: Adm1nBb5 + pool: 5 + database_tasks: false + tds_version: 7.3 + +development: + primary: + adapter: sqlserver + mode: dblib + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + + host: "10.41.82.73" + port: 1433 + database: Baclight + username: BSTI + password: BSTIBOY + tds_version: 7.3 + vhcs: + adapter: sqlserver + mode: dblib + pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> + host: "10.41.82.72" port: 1433 database: VHCS_HIPAA @@ -30,8 +78,19 @@ production: host: 10.41.82.73 port: 1433 + database: BrittonWeb username: BSTI password: BSTIBOY - password: Adm1nBb5 + database_tasks: false + tds_version: 7.3 + heb_web: + adapter: sqlserver + mode: dblib + host: 10.41.82.73 + port: 1433 + database: HEBWeb + username: SA + password: Adm1nBb5 + pool: 5 database_tasks: false tds_version: 7.3 diff --git a/config/environments/development.rb b/config/environments/development.rb index bb656d9..7ad9f5a 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -82,7 +82,8 @@ Rails.application.configure do # Apply autocorrection by RuboCop to files generated by `bin/rails generate`. # config.generators.apply_rubocop_autocorrect_after_generate! - config.active_job.queue_adapter = :solid_queue - config.solid_queue.connects_to = { database: { writing: :primary } } + config.active_job.queue_adapter = :delayed_job + # config.active_job.queue_adapter = :solid_queue + # config.solid_queue.connects_to = { database: { writing: :primary } } # config.active_job.queue_adapter = :async end diff --git a/config/environments/production.rb b/config/environments/production.rb index 6a6e8f9..5e4a6c8 100644 --- a/config/environments/production.rb +++ b/config/environments/production.rb @@ -28,7 +28,8 @@ Rails.application.configure do # Do not fall back to assets pipeline if a precompiled asset is missed. config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? - config.assets.compile = false + # config.assets.compile = false + config.assets.digest = true # Enable serving of images, stylesheets, and JavaScripts from an asset server. # config.asset_host = "http://assets.example.com" diff --git a/config/importmap.rb b/config/importmap.rb index 24606e1..27049b5 100644 --- a/config/importmap.rb +++ b/config/importmap.rb @@ -4,9 +4,9 @@ pin "application", preload: true pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true -pin_all_from "app/javascript/controllers", under: "controllers" +pin_all_from "app/javascript/controllers", under: "controllers", preload: true -pin "lucide-static", to: "https://ga.jspm.io/npm:lucide-static@0.X.X/lucide.js" +# pin "lucide-static", to: "https://ga.jspm.io/npm:lucide-static@0.X.X/lucide.js", preload: true pin "trix" pin "@rails/actiontext", to: "actiontext.js" diff --git a/config/routes.rb b/config/routes.rb index e20a14f..343ea7c 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,6 +1,10 @@ # frozen_string_literal: true Rails.application.routes.draw do + resources :providers + resources :provider_groups + resources :brokers + resources :carriers devise_for :users devise_scope :user do authenticated :user do diff --git a/config/schedule.rb b/config/schedule.rb index dc9fbd5..39c957a 100644 --- a/config/schedule.rb +++ b/config/schedule.rb @@ -9,6 +9,6 @@ every 1.day, at: ['6:00 am', '6:00 pm'] do rake "employer_automation:employer_maintenance" end -# every '0,15,30,45 7-18 * * 1-5' do -# rake "employer_automation:employer_initialize" -# end +every '0,15,30,45 7-18 * * 1-5' do + rake "employer_automation:employer_initialize" +end diff --git a/db/migrate/20260513154359_create_carriers.rb b/db/migrate/20260513154359_create_carriers.rb new file mode 100644 index 0000000..a8bedaa --- /dev/null +++ b/db/migrate/20260513154359_create_carriers.rb @@ -0,0 +1,9 @@ +class CreateCarriers < ActiveRecord::Migration[7.2] + def change + create_table :carriers do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20260513154436_create_brokers.rb b/db/migrate/20260513154436_create_brokers.rb new file mode 100644 index 0000000..e49c6dc --- /dev/null +++ b/db/migrate/20260513154436_create_brokers.rb @@ -0,0 +1,10 @@ +class CreateBrokers < ActiveRecord::Migration[7.2] + def change + create_table :brokers do |t| + t.string :name + t.belongs_to :carrier, null: true, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/migrate/20260513155053_update_employer_to_belong_to_broker.rb b/db/migrate/20260513155053_update_employer_to_belong_to_broker.rb new file mode 100644 index 0000000..40c2f8e --- /dev/null +++ b/db/migrate/20260513155053_update_employer_to_belong_to_broker.rb @@ -0,0 +1,5 @@ +class UpdateEmployerToBelongToBroker < ActiveRecord::Migration[7.2] + def change + add_reference :employers, :broker, null: true, foreign_key: true + end +end diff --git a/db/migrate/20260513162002_create_provider_groups.rb b/db/migrate/20260513162002_create_provider_groups.rb new file mode 100644 index 0000000..15cf04f --- /dev/null +++ b/db/migrate/20260513162002_create_provider_groups.rb @@ -0,0 +1,9 @@ +class CreateProviderGroups < ActiveRecord::Migration[7.2] + def change + create_table :provider_groups do |t| + t.string :name + + t.timestamps + end + end +end diff --git a/db/migrate/20260513162029_create_providers.rb b/db/migrate/20260513162029_create_providers.rb new file mode 100644 index 0000000..032896b --- /dev/null +++ b/db/migrate/20260513162029_create_providers.rb @@ -0,0 +1,13 @@ +class CreateProviders < ActiveRecord::Migration[7.2] + def change + create_table :providers do |t| + t.string :name + t.integer :pb_entity_key + t.string :tax_id + t.string :family_id + t.belongs_to :provider_group, null: true, foreign_key: true + + t.timestamps + end + end +end diff --git a/db/schema.rb b/db/schema.rb index c53771a..9573842 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,21 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema[7.2].define(version: 2026_04_30_184912) do +ActiveRecord::Schema[7.2].define(version: 2026_05_13_162029) do + create_table "brokers", force: :cascade do |t| + t.string "name" + t.bigint "carrier_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["carrier_id"], name: "index_brokers_on_carrier_id" + end + + create_table "carriers", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + create_table "delayed_jobs", force: :cascade do |t| t.integer "priority", default: 0, null: false t.integer "attempts", default: 0, null: false @@ -38,6 +52,8 @@ ActiveRecord::Schema[7.2].define(version: 2026_04_30_184912) do t.boolean "initialized", default: false t.datetime "created_at", null: false t.datetime "updated_at", null: false + t.bigint "broker_id" + t.index ["broker_id"], name: "index_employers_on_broker_id" end create_table "id_card_employer_logos", force: :cascade do |t| @@ -295,6 +311,23 @@ ActiveRecord::Schema[7.2].define(version: 2026_04_30_184912) do t.index ["id_card_plan_id"], name: "index_members_on_id_card_plan_id" end + create_table "provider_groups", force: :cascade do |t| + t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + end + + create_table "providers", force: :cascade do |t| + t.string "name" + t.integer "pb_entity_key" + t.string "tax_id" + t.string "family_id" + t.bigint "provider_group_id" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["provider_group_id"], name: "index_providers_on_provider_group_id" + end + create_table "report_comparison_errors", force: :cascade do |t| t.string "card_field" t.string "new_value" @@ -550,6 +583,8 @@ ActiveRecord::Schema[7.2].define(version: 2026_04_30_184912) do t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, where: "([reset_password_token] IS NOT NULL)" end + add_foreign_key "brokers", "carriers" + add_foreign_key "employers", "brokers" add_foreign_key "id_card_employer_logos", "id_card_setups", column: "setup_id" add_foreign_key "id_card_field_exception_items", "id_card_field_exceptions", column: "field_exception_id" add_foreign_key "id_card_field_exception_items", "id_card_network_logos", column: "network_logo_id" @@ -564,6 +599,7 @@ ActiveRecord::Schema[7.2].define(version: 2026_04_30_184912) do add_foreign_key "id_card_setups", "id_card_rx_sections", column: "rx_section_id" add_foreign_key "members", "employers" add_foreign_key "members", "id_card_plans" + add_foreign_key "providers", "provider_groups" add_foreign_key "report_comparison_errors", "report_employer_card_comparisons", column: "employer_card_comparison_id" add_foreign_key "report_comparison_errors", "report_member_card_comparisons", column: "member_card_comparison_id" add_foreign_key "report_member_card_comparisons", "report_employer_card_comparisons", column: "employer_card_comparison_id" diff --git a/db/seeds.rb b/db/seeds.rb index 0f8f907..828a970 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -8,8 +8,8 @@ "seed_tasks:build_vendors", "seed_tasks:build_carriers", - "seed_tasks:build_brokers", "seed_tasks:build_employers", + "seed_tasks:build_brokers", "seed_tasks:determine_card_templates", "seed_tasks:determine_network_fields", diff --git a/docker-compose.yaml b/docker-compose.yaml index b572828..2c7eb61 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -1,14 +1,17 @@ services: web: build: - context: . + context: ./ + dockerfile: development.Dockerfile volumes: - - .:/rails + - .:/usr/src/app + - bundle:/usr/local/bundle ports: - "3002:3002" environment: - HISTFILE=/usr/src/app/log/.bash_history - - RAILS_ENV=production + - RAILS_ENV=development + # - TAILWIND_POLLING=true - PUID=1000 - PGID=100 tty: true @@ -39,7 +42,7 @@ services: # cron: # build: # context: ./ - # dockerfile: development3.Dockerfile + # dockerfile: development.Dockerfile # command: ./bin/cron-entrypoint # volumes: # - .:/usr/src/app diff --git a/lib/generators/legacy_db_model/legacy_db_model_generator.rb b/lib/generators/legacy_db_model/legacy_db_model_generator.rb index 63e2956..8f2c869 100644 --- a/lib/generators/legacy_db_model/legacy_db_model_generator.rb +++ b/lib/generators/legacy_db_model/legacy_db_model_generator.rb @@ -14,7 +14,7 @@ class LegacyDbModelGenerator < Rails::Generators::Base @module = 'BrittonWeb'.constantize @file_folder = 'britton_web' elsif db_name == 'HEBWeb' - @db_record = 'WebRecord'.constantize + @db_record = 'HebWebRecord'.constantize @module = 'HebWeb'.constantize @file_folder = 'heb_web' else diff --git a/lib/tasks/employer_automation.rake b/lib/tasks/employer_automation.rake index 29a5741..0f79199 100644 --- a/lib/tasks/employer_automation.rake +++ b/lib/tasks/employer_automation.rake @@ -12,11 +12,17 @@ namespace :employer_automation do desc "Employer Initialization Automation Test" # rake employer_automation:employer_initialize_test task employer_initialize_test: :environment do - if (missing_keychain = Employer.missing_keychain_initialization).exists? + missing_keychain = Employer.missing_keychain_initialization + missing_plans = Employer.missing_plans_initialization + missing_members = Employer.missing_members_initialization + + if missing_keychain.exists? missing_keychain.map(&:sync_with_vhcs) - elsif (missing_plans = Employer.missing_plans_initialization).exists? + end + if missing_plans.exists? missing_plans.map(&:sync_plans_with_vhcs) - elsif (missing_members = Employer.missing_members_initialization).exists? + end + if missing_members.exists? missing_members.map(&:sync_members_with_vhcs) end end diff --git a/lib/tasks/seed_tasks.rake b/lib/tasks/seed_tasks.rake index 9055d77..4eae9aa 100644 --- a/lib/tasks/seed_tasks.rake +++ b/lib/tasks/seed_tasks.rake @@ -169,12 +169,30 @@ namespace :seed_tasks do # rake seed_tasks:build_carriers task build_carriers: :environment do puts "Importing Carriers" + Carrier.create!(name: "Level360") end desc "Build Initial Brokers" # rake seed_tasks:build_brokers task build_brokers: :environment do - puts "Importing Brokers" + puts "Creating Brokers and connecting to Employers" + broker_employers = [ + {name: "Tom McSwain", pl_plan_keys: ["4", "5", "13", "16", "19", "21", "23", "33", "62", "65"]}, + {name: "Rus Clark", pl_plan_keys: ["66"]}, + {name: "Keven Locht", pl_plan_keys: ["54","69"]}, + {name: "Mike Carraway", pl_plan_keys: ["48","61"]}, + {name: "Brian Puckett", pl_plan_keys: ["57","59","68"]}, + {name: "Ethan Sale", pl_plan_keys: ["58"]}, + {name: "Todd Lawrence", pl_plan_keys: ["67"]}, + {name: "Brian Mercier", pl_plan_keys: ["51", "55", "60", "63"]}, + {name: "John Kern", pl_plan_keys: ["53"]} + ] + level360 = Carrier.first + broker_employers.each do |broker_map| + new_broker = Broker.create!(name: broker_map[:name], carrier: level360) + Employer.where(pl_plan_key: broker_map[:pl_plan_keys]).update_all(broker_id: new_broker.id) + end + # Broker.create!(name: "Tom McSwain", carrier: level360) end desc "Build Initial Employers" diff --git a/prod.docker-compose.yaml b/prod.docker-compose.yaml new file mode 100644 index 0000000..b572828 --- /dev/null +++ b/prod.docker-compose.yaml @@ -0,0 +1,57 @@ +services: + web: + build: + context: . + volumes: + - .:/rails + ports: + - "3002:3002" + environment: + - HISTFILE=/usr/src/app/log/.bash_history + - RAILS_ENV=production + - PUID=1000 + - PGID=100 + tty: true + stdin_open: true + # healthcheck: + # test: ["CMD", "curl", "-f", "http://localhost:3002/up"] + # interval: 5s + # timeout: 3s + # retries: 10 + # start_period: 10s + # depends_on: + # db: + # condition: service_healthy + # db: + # build: + # context: . + # dockerfile: Dockerfile.db + # volumes: + # - ./mssql-data:/var/opt/mssql + # ports: + # - "1434:1434" + # healthcheck: + # test: ["CMD", "/opt/mssql-tools/bin/sqlcmd", "-Usa", "-PBr1tt0nPassw0rd", "-Q", "select 1"] + # interval: 10s + # timeout: 3s + # retries: 10 + # start_period: 10s + # cron: + # build: + # context: ./ + # dockerfile: development3.Dockerfile + # command: ./bin/cron-entrypoint + # volumes: + # - .:/usr/src/app + # - bundle:/usr/local/bundle + # environment: + # - RAILS_ENV=development + # - PUID=1000 + # - PGID=100 + # depends_on: + # web: + # condition: service_healthy + # - db +volumes: + # redis_data: + bundle: