jasper print speed refactor working

This commit is contained in:
Jason Jordan
2026-03-27 08:04:37 -04:00
parent a43c8bf6b5
commit 9f306d3150
33 changed files with 1015 additions and 168 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ inherit_gem:
rubocop-rails-omakase: rubocop.yml rubocop-rails-omakase: rubocop.yml
AllCops: AllCops:
TargetRubyVersion: 3.3.9 TargetRubyVersion: 3.4.8
TargetRailsVersion: 7.2.2 TargetRailsVersion: 7.2.2
DisabledByDefault: true DisabledByDefault: true
Exclude: Exclude:
+1 -1
View File
@@ -1 +1 @@
3.3.9 3.4.8
+2 -2
View File
@@ -83,9 +83,9 @@ gem 'devise'
gem 'pundit' gem 'pundit'
gem "tailwindcss-rails" gem "tailwindcss-rails"
gem 'docx' gem 'docx'
gem 'rubyzip'
gem 'httparty' gem 'httparty'
gem 'combine_pdf' gem 'combine_pdf'
gem 'rails_icons' gem 'rails_icons'
gem 'fastimage' gem 'fastimage'
gem 'rubyzip', require: 'zip' gem 'rubyzip', require: 'zip'
gem "solid_queue"
+88 -103
View File
@@ -56,7 +56,7 @@ GEM
activemodel (= 7.2.3) activemodel (= 7.2.3)
activesupport (= 7.2.3) activesupport (= 7.2.3)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activerecord-sqlserver-adapter (7.2.8) activerecord-sqlserver-adapter (7.2.9)
activerecord (~> 7.2.0) activerecord (~> 7.2.0)
tiny_tds tiny_tds
activestorage (7.2.3) activestorage (7.2.3)
@@ -77,21 +77,21 @@ GEM
minitest (>= 5.1) minitest (>= 5.1)
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0, >= 2.0.5)
addressable (2.8.7) addressable (2.8.9)
public_suffix (>= 2.0.2, < 7.0) public_suffix (>= 2.0.2, < 8.0)
ast (2.4.3) ast (2.4.3)
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.20) bcrypt (3.1.22)
benchmark (0.5.0) benchmark (0.5.0)
bigdecimal (3.3.1) bigdecimal (4.0.1)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.18.6) bootsnap (1.23.0)
msgpack (~> 1.2) msgpack (~> 1.2)
brakeman (7.1.1) brakeman (8.0.4)
racc racc
builder (3.3.0) builder (3.3.0)
bundler-audit (0.9.2) bundler-audit (0.9.3)
bundler (>= 1.2.0, < 3) bundler (>= 1.2.0)
thor (~> 1.0) thor (~> 1.0)
capybara (3.40.0) capybara (3.40.0)
addressable addressable
@@ -102,20 +102,20 @@ GEM
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0) regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2) xpath (~> 3.2)
cgi (0.5.0) cgi (0.5.1)
coderay (1.1.3) coderay (1.1.3)
combine_pdf (1.0.31) combine_pdf (1.0.31)
matrix matrix
ruby-rc4 (>= 0.1.5) ruby-rc4 (>= 0.1.5)
concurrent-ruby (1.3.5) concurrent-ruby (1.3.6)
connection_pool (2.5.4) connection_pool (3.0.2)
crass (1.0.6) crass (1.0.6)
csv (3.3.5) csv (3.3.5)
date (3.5.0) date (3.5.1)
devise (4.9.4) devise (5.0.3)
bcrypt (~> 3.0) bcrypt (~> 3.0)
orm_adapter (~> 0.1) orm_adapter (~> 0.1)
railties (>= 4.1.0) railties (>= 7.0)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
diff-lcs (1.6.2) diff-lcs (1.6.2)
@@ -123,34 +123,42 @@ GEM
nokogiri (~> 1.13, >= 1.13.0) nokogiri (~> 1.13, >= 1.13.0)
rubyzip (>= 2.0, < 4) rubyzip (>= 2.0, < 4)
drb (2.2.3) drb (2.2.3)
erb (5.1.3) erb (6.0.2)
erubi (1.13.1) erubi (1.13.1)
fastimage (2.4.0) et-orbi (1.4.0)
tzinfo
fastimage (2.4.1)
fugit (1.12.1)
et-orbi (~> 1.4)
raabro (~> 1.4)
globalid (1.3.0) globalid (1.3.0)
activesupport (>= 6.1) activesupport (>= 6.1)
httparty (0.23.2) httparty (0.24.2)
csv csv
mini_mime (>= 1.0.0) mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
i18n (1.14.7) i18n (1.14.8)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
importmap-rails (2.2.2) icons (0.8.1)
nokogiri (~> 1.16, >= 1.16.4)
importmap-rails (2.2.3)
actionpack (>= 6.0.0) actionpack (>= 6.0.0)
activesupport (>= 6.0.0) activesupport (>= 6.0.0)
railties (>= 6.0.0) railties (>= 6.0.0)
io-console (0.8.1) io-console (0.8.2)
irb (1.15.3) irb (1.17.0)
pp (>= 0.6.0) pp (>= 0.6.0)
prism (>= 1.3.0)
rdoc (>= 4.0.0) rdoc (>= 4.0.0)
reline (>= 0.4.2) reline (>= 0.4.2)
jbuilder (2.14.1) jbuilder (2.14.1)
actionview (>= 7.0.0) actionview (>= 7.0.0)
activesupport (>= 7.0.0) activesupport (>= 7.0.0)
json (2.15.2) json (2.19.2)
language_server-protocol (3.17.0.5) language_server-protocol (3.17.0.5)
lint_roller (1.1.0) lint_roller (1.1.0)
logger (1.7.0) logger (1.7.0)
loofah (2.24.1) loofah (2.25.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
mail (2.9.0) mail (2.9.0)
@@ -163,11 +171,13 @@ GEM
matrix (0.4.3) matrix (0.4.3)
method_source (1.1.0) method_source (1.1.0)
mini_mime (1.1.5) mini_mime (1.1.5)
minitest (5.26.0) minitest (6.0.2)
drb (~> 2.0)
prism (~> 1.5)
msgpack (1.8.0) msgpack (1.8.0)
multi_xml (0.7.2) multi_xml (0.8.1)
bigdecimal (~> 3.1) bigdecimal (>= 3.1, < 5)
net-imap (0.5.12) net-imap (0.6.3)
date date
net-protocol net-protocol
net-pop (0.1.2) net-pop (0.1.2)
@@ -177,46 +187,34 @@ GEM
net-smtp (0.5.1) net-smtp (0.5.1)
net-protocol net-protocol
nio4r (2.7.5) nio4r (2.7.5)
nokogiri (1.18.10-aarch64-linux-gnu) nokogiri (1.19.2-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.10-aarch64-linux-musl)
racc (~> 1.4)
nokogiri (1.18.10-arm-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.10-arm-linux-musl)
racc (~> 1.4)
nokogiri (1.18.10-arm64-darwin)
racc (~> 1.4)
nokogiri (1.18.10-x86_64-darwin)
racc (~> 1.4)
nokogiri (1.18.10-x86_64-linux-gnu)
racc (~> 1.4)
nokogiri (1.18.10-x86_64-linux-musl)
racc (~> 1.4) racc (~> 1.4)
orm_adapter (0.5.0) orm_adapter (0.5.0)
parallel (1.27.0) parallel (1.27.0)
parser (3.3.10.0) parser (3.3.10.2)
ast (~> 2.4.1) ast (~> 2.4.1)
racc racc
pp (0.6.3) pp (0.6.3)
prettyprint prettyprint
prettyprint (0.2.0) prettyprint (0.2.0)
prism (1.6.0) prism (1.9.0)
pry (0.15.2) pry (0.16.0)
coderay (~> 1.1) coderay (~> 1.1)
method_source (~> 1.0) method_source (~> 1.0)
reline (>= 0.6.0)
pry-rails (0.3.11) pry-rails (0.3.11)
pry (>= 0.13.0) pry (>= 0.13.0)
psych (5.2.6) psych (5.3.1)
date date
stringio stringio
public_suffix (6.0.2) public_suffix (7.0.5)
puma (6.6.1) puma (6.6.1)
nio4r (~> 2.0) nio4r (~> 2.0)
pundit (2.5.2) pundit (2.5.2)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
rack (3.2.4) rack (3.2.5)
rack-mini-profiler (4.0.1) rack-mini-profiler (4.0.1)
rack (>= 1.2.0) rack (>= 1.2.0)
rack-session (2.1.1) rack-session (2.1.1)
@@ -224,7 +222,7 @@ GEM
rack (>= 3.0.0) rack (>= 3.0.0)
rack-test (2.2.0) rack-test (2.2.0)
rack (>= 1.3) rack (>= 1.3)
rackup (2.2.1) rackup (2.3.1)
rack (>= 3) rack (>= 3)
rails (7.2.3) rails (7.2.3)
actioncable (= 7.2.3) actioncable (= 7.2.3)
@@ -244,11 +242,11 @@ GEM
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.6.2) rails-html-sanitizer (1.7.0)
loofah (~> 2.21) loofah (~> 2.25)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
rails_icons (1.5.1) rails_icons (1.7.1)
nokogiri (~> 1.16, >= 1.16.4) icons (~> 0.8.1)
rails (>= 7.0) rails (>= 7.0)
railties (7.2.3) railties (7.2.3)
actionpack (= 7.2.3) actionpack (= 7.2.3)
@@ -262,12 +260,12 @@ GEM
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.3.1) rake (13.3.1)
rdoc (6.15.1) rdoc (7.2.0)
erb erb
psych (>= 4.0.0) psych (>= 4.0.0)
tsort tsort
regexp_parser (2.11.3) regexp_parser (2.11.3)
reline (0.6.2) reline (0.6.3)
io-console (~> 0.5) io-console (~> 0.5)
responders (3.2.0) responders (3.2.0)
actionpack (>= 7.0) actionpack (>= 7.0)
@@ -278,19 +276,19 @@ GEM
rspec-expectations (3.13.5) rspec-expectations (3.13.5)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-mocks (3.13.7) rspec-mocks (3.13.8)
diff-lcs (>= 1.2.0, < 2.0) diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.13.0) rspec-support (~> 3.13.0)
rspec-rails (8.0.2) rspec-rails (8.0.4)
actionpack (>= 7.2) actionpack (>= 7.2)
activesupport (>= 7.2) activesupport (>= 7.2)
railties (>= 7.2) railties (>= 7.2)
rspec-core (~> 3.13) rspec-core (>= 3.13.0, < 5.0.0)
rspec-expectations (~> 3.13) rspec-expectations (>= 3.13.0, < 5.0.0)
rspec-mocks (~> 3.13) rspec-mocks (>= 3.13.0, < 5.0.0)
rspec-support (~> 3.13) rspec-support (>= 3.13.0, < 5.0.0)
rspec-support (3.13.6) rspec-support (3.13.7)
rubocop (1.81.7) rubocop (1.86.0)
json (~> 2.3) json (~> 2.3)
language_server-protocol (~> 3.17.0.2) language_server-protocol (~> 3.17.0.2)
lint_roller (~> 1.1.0) lint_roller (~> 1.1.0)
@@ -298,17 +296,17 @@ GEM
parser (>= 3.3.0.2) parser (>= 3.3.0.2)
rainbow (>= 2.2.2, < 4.0) rainbow (>= 2.2.2, < 4.0)
regexp_parser (>= 2.9.3, < 3.0) regexp_parser (>= 2.9.3, < 3.0)
rubocop-ast (>= 1.47.1, < 2.0) rubocop-ast (>= 1.49.0, < 2.0)
ruby-progressbar (~> 1.7) ruby-progressbar (~> 1.7)
unicode-display_width (>= 2.4.0, < 4.0) unicode-display_width (>= 2.4.0, < 4.0)
rubocop-ast (1.47.1) rubocop-ast (1.49.1)
parser (>= 3.3.7.2) parser (>= 3.3.7.2)
prism (~> 1.4) prism (~> 1.7)
rubocop-performance (1.26.1) rubocop-performance (1.26.1)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (>= 1.75.0, < 2.0) rubocop (>= 1.75.0, < 2.0)
rubocop-ast (>= 1.47.1, < 2.0) rubocop-ast (>= 1.47.1, < 2.0)
rubocop-rails (2.33.4) rubocop-rails (2.34.3)
activesupport (>= 4.2.0) activesupport (>= 4.2.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rack (>= 1.1) rack (>= 1.1)
@@ -318,19 +316,26 @@ GEM
rubocop (>= 1.72) rubocop (>= 1.72)
rubocop-performance (>= 1.24) rubocop-performance (>= 1.24)
rubocop-rails (>= 2.30) rubocop-rails (>= 2.30)
rubocop-rspec (3.7.0) rubocop-rspec (3.9.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1) rubocop (~> 1.81)
ruby-progressbar (1.13.0) ruby-progressbar (1.13.0)
ruby-rc4 (0.1.5) ruby-rc4 (0.1.5)
rubyzip (3.2.2) rubyzip (3.2.2)
securerandom (0.4.1) securerandom (0.4.1)
selenium-webdriver (4.38.0) selenium-webdriver (4.41.0)
base64 (~> 0.2) base64 (~> 0.2)
logger (~> 1.4) logger (~> 1.4)
rexml (~> 3.2, >= 3.2.5) rexml (~> 3.2, >= 3.2.5)
rubyzip (>= 1.2.2, < 4.0) rubyzip (>= 1.2.2, < 4.0)
websocket (~> 1.0) websocket (~> 1.0)
solid_queue (1.4.0)
activejob (>= 7.1)
activerecord (>= 7.1)
concurrent-ruby (>= 1.3.1)
fugit (~> 1.11)
railties (>= 7.1)
thor (>= 1.3.1)
sprockets (4.2.2) sprockets (4.2.2)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
logger logger
@@ -341,38 +346,24 @@ GEM
sprockets (>= 3.0.0) sprockets (>= 3.0.0)
stimulus-rails (1.3.4) stimulus-rails (1.3.4)
railties (>= 6.0.0) railties (>= 6.0.0)
stringio (3.1.7) stringio (3.2.0)
tailwindcss-rails (4.4.0) tailwindcss-rails (4.4.0)
railties (>= 7.0.0) railties (>= 7.0.0)
tailwindcss-ruby (~> 4.0) tailwindcss-ruby (~> 4.0)
tailwindcss-ruby (4.1.16) tailwindcss-ruby (4.2.1-x86_64-linux-gnu)
tailwindcss-ruby (4.1.16-aarch64-linux-gnu) thor (1.5.0)
tailwindcss-ruby (4.1.16-aarch64-linux-musl) timeout (0.6.1)
tailwindcss-ruby (4.1.16-arm64-darwin) tiny_tds (3.4.0-x86_64-linux-gnu)
tailwindcss-ruby (4.1.16-x86_64-darwin) bigdecimal (>= 2.0.0)
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) tsort (0.2.0)
turbo-rails (2.0.20) turbo-rails (2.0.23)
actionpack (>= 7.1.0) actionpack (>= 7.1.0)
railties (>= 7.1.0) railties (>= 7.1.0)
tzinfo (2.0.6) tzinfo (2.0.6)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
unicode-display_width (3.2.0) unicode-display_width (3.2.0)
unicode-emoji (~> 4.1) unicode-emoji (~> 4.1)
unicode-emoji (4.1.0) unicode-emoji (4.2.0)
useragent (0.16.11) useragent (0.16.11)
warden (1.2.9) warden (1.2.9)
rack (>= 2.0.9) rack (>= 2.0.9)
@@ -388,17 +379,10 @@ GEM
websocket-extensions (0.1.5) websocket-extensions (0.1.5)
xpath (3.2.0) xpath (3.2.0)
nokogiri (~> 1.8) nokogiri (~> 1.8)
zeitwerk (2.7.3) zeitwerk (2.7.5)
PLATFORMS PLATFORMS
aarch64-linux-gnu x86_64-linux
aarch64-linux-musl
arm-linux-gnu
arm-linux-musl
arm64-darwin
x86_64-darwin
x86_64-linux-gnu
x86_64-linux-musl
DEPENDENCIES DEPENDENCIES
activerecord-sqlserver-adapter activerecord-sqlserver-adapter
@@ -425,6 +409,7 @@ DEPENDENCIES
rubocop-rspec rubocop-rspec
rubyzip rubyzip
selenium-webdriver selenium-webdriver
solid_queue
sprockets-rails sprockets-rails
stimulus-rails stimulus-rails
tailwindcss-rails tailwindcss-rails
@@ -437,4 +422,4 @@ RUBY VERSION
ruby 3.4.8p72 ruby 3.4.8p72
BUNDLED WITH BUNDLED WITH
2.5.22 2.6.9
+1 -1
View File
@@ -72,7 +72,7 @@ class EmployersController < ApplicationController
def import def import
word_doc = params[:employer][:import_from_word] word_doc = params[:employer][:import_from_word]
if word_doc.present? && word_doc.is_a?(ActionDispatch::Http::UploadedFile) if word_doc.present? && word_doc.is_a?(ActionDispatch::Http::UploadedFile)
@employer = WordDocProcessor.new(word_doc.tempfile).call @employer = BenefitsWordDocService::WordDocProcessor.new(word_doc.tempfile).call
@employer.save @employer.save
redirect_to employer_path(@employer.slug), notice: 'Employer Imported' redirect_to employer_path(@employer.slug), notice: 'Employer Imported'
else else
+1 -1
View File
@@ -70,7 +70,7 @@ module IdCard
slug = params[:id] slug = params[:id]
@employer = Employer.find_by(slug: slug) @employer = Employer.find_by(slug: slug)
end end
cards_pdf = IdCardPrinterService::EmployerCardsGenerator.new(@employer, "PrintCard").call cards_pdf = IdCardPrinterService::CardsGenerator.new(@employer.employer_member_keys, "PrintCard").call
send_data cards_pdf.to_pdf, send_data cards_pdf.to_pdf,
filename: "#{@employer.name.parameterize(separator: "_")}_print_cards_#{Date.today}.pdf", filename: "#{@employer.name.parameterize(separator: "_")}_print_cards_#{Date.today}.pdf",
+90
View File
@@ -0,0 +1,90 @@
class ProcessIdCardDataJob < ApplicationJob
queue_as :default
def perform(member_key, field_exception_ids, has_divisions = false)
member = Member.find_by(pb_entity_key: member_key)
effect_date = determine_eff_date(member)
if effect_date
member_card = @base_card.dup
member_attributes = {
full_name: member.id_card_display_name,
full_name_last_name_first: member.name,
primary_mb_member_key: member.pb_entity_key,
family_id: member.family_id,
plan_id: member.id_card_plan_id,
medical_eff_date: effect_date.strftime("%m/%d/%Y")
}
dependent_attributes = get_dependent_fields(member)
if dependent_attributes.present?
member_attributes.merge!(dependent_attributes)
end
if has_divisions
member_attributes.merge!({employer_name: member.division})
end
if field_exception_ids.present?
exceptions_attributes = {}
field_exceptions = IdCard::FieldException.where(id: field_exception_ids)
member_exception_values = member.id_card_field_exception_values
field_exceptions.each do |fe|
if member_exception_values[fe.field_type] == fe.field_value
fe.field_exception_items.each do |fei|
if fei.field_value.present?
exceptions_attributes[fei.field_name] = fei.field_value
elsif fei.provider_section_id.present?
provider_attributes = IdCard::ProviderSection.find(fei.provider_section_id).attributes.with_indifferent_access.slice(
:provider_line_1, :provider_line_2, :provider_line_3, :provider_line_4, :provider_line_5, :provider_line_6,
:provider_line_7, :provider_line_8, :provider_line_9, :provider_line_10, :provider_line_11, :provider_line_12,
:claim_to_1, :claim_to_2, :claim_to_3, :claim_to_4, :claim_to_5, :claim_to_6,
:claim_to_7, :claim_to_8, :claim_to_9, :claim_to_10, :claim_to_11, :claim_to_12
)
exceptions_attributes.merge!(provider_attributes)
elsif fei.network_logo_id.present?
exceptions_attributes.merge!(network_logo_id: fei.network_logo_id)
exceptions_attributes.merge!(network_logo_filename: fei.network_logo.filename)
end
end
end
end
member_attributes.merge!(exceptions_attributes)
end
member_card = IdCard::PrintData.find_by(pl_plan_key: member.pl_plan_key, plan_id: member.id_card_plan_id, primary_mb_member_key: nil).dup
member_card.assign_attributes(member_attributes)
member_card.save
end
true
# BatchProcess.increment_counter(:completed_jobs, batch_process_id)
end
private
def determine_eff_date(member)
participation = Vhcs::PbProductParticipation.joins('INNER JOIN "PBCoveredEntities" ON "PBProductParticipation"."PBProductParticipationKey" = "PBCoveredEntities"."PBProductParticipationKey"').where('"PBCoveredEntities"."PBEntityKey" = ?', member.pb_entity_key).last
in_effect = participation.in_effect
out_of_effect = participation.out_of_effect
if in_effect <= (Date.today + 90.days) && (out_of_effect - 1.day) > Date.today && out_of_effect > in_effect
in_effect
else
false
end
end
def get_dependent_fields(member)
dependent_attributes = {}
dependents = Vhcs::VwmbMember.where(pl_plan_key: member.pl_plan_key, family_id: member.family_id).where.not(pb_entity_key: member.pb_entity_key)
dependents.each do |dep|
dependent_name = dep.first_name + ' ' + dep.last_name
dependent_attributes["dependent_#{dep.sequence_number - 1}".to_sym] = dependent_name
end
dependent_attributes
end
end
+7
View File
@@ -46,6 +46,13 @@ class Employer < ApplicationRecord
false false
end end
def employer_member_keys
{
pl_plan_key: self.pl_plan_key,
member_keys: self.members.pluck(:pb_entity_key)
}
end
def name_to_logo_filename(extension) def name_to_logo_filename(extension)
self.employer_trim_name(self.name).titleize.gsub(/[^a-zA-Z]/, '').concat('Logo').concat(extension.downcase) self.employer_trim_name(self.name).titleize.gsub(/[^a-zA-Z]/, '').concat('Logo').concat(extension.downcase)
end end
+4
View File
@@ -36,6 +36,10 @@ module IdCard
plan plan
end end
def has_field_exceptions?
self.field_exceptions.present?
end
def self.permitted_params(params) def self.permitted_params(params)
params.require(:id_card_setup).permit( params.require(:id_card_setup).permit(
:print_name, :print_name,
+11
View File
@@ -2,5 +2,16 @@ class Member < ApplicationRecord
belongs_to :id_card_plan, class_name: 'IdCard::Plan', optional: true belongs_to :id_card_plan, class_name: 'IdCard::Plan', optional: true
belongs_to :employer belongs_to :employer
def id_card_field_exception_values
address = Vhcs::PbEntityAddress.find_by(pb_entity_key: self.pb_entity_key)
{
zipcode: address.zip,
state: address.state,
family_id: self.family_id
}
end
end end
+47
View File
@@ -0,0 +1,47 @@
module Vhcs
class PbEntityAddress < VhcsRecord
self.table_name = 'PBEntityAddress'
alias_attribute :pb_entity_address_key, :PBEntityAddressKey
alias_attribute :pb_entity_key, :PBEntityKey
alias_attribute :address_type_id, :AddressTypeID
alias_attribute :street_line_1, :StreetLine1
alias_attribute :street_line_2, :StreetLine2
alias_attribute :city, :City
alias_attribute :state, :State
alias_attribute :zip, :Zip
alias_attribute :country_code, :CountryCode
alias_attribute :county, :County
alias_attribute :override_pb_entity_address_key, :OverridePBEntityAddressKey
alias_attribute :when_last_changed, :WhenLastChanged
alias_attribute :who_last_changed, :WhoLastChanged
alias_attribute :full_address_to_use, :FullAddressToUse
alias_attribute :country_sub_div, :CountrySubDiv
alias_attribute :full_address, :FullAddress
def attributes
rails_like = {
pb_entity_address_key: self.pb_entity_address_key,
pb_entity_key: self.pb_entity_key,
address_type_id: self.address_type_id,
street_line_1: self.street_line_1,
street_line_2: self.street_line_2,
city: self.city,
state: self.state,
zip: self.zip,
country_code: self.country_code,
county: self.county,
override_pb_entity_address_key: self.override_pb_entity_address_key,
when_last_changed: self.when_last_changed,
who_last_changed: self.who_last_changed,
full_address_to_use: self.full_address_to_use,
country_sub_div: self.country_sub_div,
full_address: self.full_address,
}
super.merge(rails_like)
end
end
end
@@ -0,0 +1,180 @@
module IdCardPrinterService
class CardDataFormatter
def initialize(employers_member_keys)
# @employer = employer
@employers_member_keys = employers_member_keys
# @employer = Employer.includes(id_card_setup: [:provider_section, :rx_section]).find_by(pl_plan_key: pl_plan_key)
# @card_setup = @employer.id_card_setup
end
def call
# blank_card = IdCard::PrintData.new()
# @employer_cards = []
print_card_futures = []
@employers_member_keys.each do |emk|
pl_plan_key = emk[:pl_plan_key]
@member_keys = emk[:member_keys]
@employer = Employer.includes(id_card_setup: [:provider_section, :rx_section]).find_by(pl_plan_key: pl_plan_key)
@card_setup = @employer.id_card_setup
base_card = initialize_employer_base_card()
create_plan_base_cards(base_card)
employer_card_futures = create_member_cards_async()
print_card_futures << employer_card_futures
end
print_card_futures.flatten.map(&:value)
end
private
def initialize_employer_base_card
employer_attributes = {
pl_plan_key: @employer.pl_plan_key,
group_number: @employer.group_number,
rx_group: @card_setup.rx_group_number,
network_provider: @card_setup.network_provider,
network_logo_id: @card_setup.network_logo_id,
network_logo_filename: @card_setup.network_logo.filename,
employer_logo_filename: @card_setup.employer_logo.filename
}
unless @card_setup.has_divisions
employer_attributes.merge!({employer_name: @card_setup.print_name})
end
rx_attributes = @card_setup.rx_section.attributes.with_indifferent_access.slice(
:customer_service,
:web_url
)
provider_attributes = @card_setup.provider_section.attributes.with_indifferent_access.slice(
:provider_line_1, :provider_line_2, :provider_line_3, :provider_line_4, :provider_line_5, :provider_line_6,
:provider_line_7, :provider_line_8, :provider_line_9, :provider_line_10, :provider_line_11, :provider_line_12,
:claim_to_1, :claim_to_2, :claim_to_3, :claim_to_4, :claim_to_5, :claim_to_6,
:claim_to_7, :claim_to_8, :claim_to_9, :claim_to_10, :claim_to_11, :claim_to_12
)
selected_attributes = employer_attributes.merge(rx_attributes).merge(provider_attributes)
# blank_card.assign_attributes(selected_attributes)
IdCard::PrintData.new(selected_attributes)
end
def create_plan_base_cards(common_fields_card)
needed_plans_ids = @employer.members.where(pb_entity_key: @member_keys).distinct.pluck(:id_card_plan_id)
needed_plans = @card_setup.plans.where(id: needed_plans_ids)
needed_plans.each do |plan|
selected_attributes = { plan_id: plan.id }
plan.plan_benefits.each do |bene|
selected_attributes["benefit_desc_#{bene.sequence}".to_sym] = bene.benefit_desc
selected_attributes["benefit_#{bene.sequence}".to_sym] = bene.benefit
end
plan_base_card = common_fields_card.dup
plan_base_card.assign_attributes(selected_attributes)
plan_base_card.save
end
end
def create_member_cards_async
field_exceptions = @card_setup.field_exceptions.pluck(:id)
mmember_card_futures = @member_keys.map do |member_key|
Concurrent::Future.execute do
ActiveRecord::Base.connection_pool.with_connection do
ProcessIdCardDataJob.perform_now(member_key, field_exceptions, @card_setup.has_divisions)
end
end
end
mmember_card_futures
# batch_process = BatchProcess.create!(total_jobs: @member_keys.count)
# @member_keys.each do |member_key|
# ProcessIdCardDataJob.perform_later(member_key, @card_setup.has_divisions, batch_process.id)
# end
# @batch_id = batch_process.id
# @members.each do |me|
# effect_date = determine_eff_date(me)
# if effect_date
# member_card = @base_card.dup
# member_attributes = {
# full_name: me.id_card_display_name,
# full_name_last_name_first: me.name,
# primary_mb_member_key: me.pb_entity_key,
# family_id: me.family_id,
# plan_id: me.id_card_plan_id,
# medical_eff_date: effect_date.strftime("%m/%d/%Y")
# }
# if @card_setup.has_divisions
# member_attributes.merge!({employer_name: me.division})
# end
# dependent_attributes = get_dependent_fields(me)
# if dependent_attributes.present?
# selected_attributes = member_attributes.merge(dependent_attributes)
# else
# selected_attributes = member_attributes
# end
# member_card.assign_attributes(selected_attributes)
# @employer_cards.push(member_card)
# end
# end
end
# def set_network_fields
# selected_attributes = @employer.card_provider.attributes.with_indifferent_access.slice(
# :provider_line_1, :provider_line_2, :provider_line_3, :provider_line_4, :provider_line_5, :provider_line_6,
# :provider_line_7, :provider_line_8, :provider_line_9, :provider_line_10, :provider_line_11, :provider_line_12,
# :claim_to_1, :claim_to_2, :claim_to_3, :claim_to_4, :claim_to_5, :claim_to_6,
# :claim_to_7, :claim_to_8, :claim_to_9, :claim_to_10, :claim_to_11, :claim_to_12
# )
# @employer_cards.all do |card|
# card.assign_attributes(selected_attributes)
# end
# end
# def set_rx_fields
# # fairos_information = Vhcs::HlrxCrosRef.where(pl_plan_key: 52).first
# selected_attributes = @employer.card_rx.attributes.with_indifferent_access.slice(
# :customer_service,
# :web_url
# )
# @employer_cards.all do |card|
# card.assign_attributes(selected_attributes)
# end
# end
def determine_eff_date(member)
participation = Vhcs::PbProductParticipation.joins('INNER JOIN "PBCoveredEntities" ON "PBProductParticipation"."PBProductParticipationKey" = "PBCoveredEntities"."PBProductParticipationKey"').where('"PBCoveredEntities"."PBEntityKey" = ?', member.pb_entity_key).last
in_effect = participation.in_effect
out_of_effect = participation.out_of_effect
if in_effect <= (Date.today + 90.days) && (out_of_effect - 1.day) > Date.today && out_of_effect > in_effect
in_effect
else
false
end
end
def get_dependent_fields(member)
dependent_attributes = {}
dependents = @group_dependents.where(family_id: member.family_id).where.not(pb_entity_key: member.pb_entity_key)
dependents.each do |dep|
dependent_name = dep.first_name + ' ' + dep.last_name
dependent_attributes["dependent_#{dep.sequence_number - 1}".to_sym] = dependent_name
end
dependent_attributes
end
end
end
@@ -0,0 +1,68 @@
module IdCardPrinterService
class CardsGenerator
def initialize(employers_member_keys, layout, zip=false)
@employers_member_keys = Array.wrap(employers_member_keys)
@layout = layout
@zip = zip
end
def call
pl_plan_keys = @employers_member_keys.map { |emk| emk[:pl_plan_key] }
IdCard::PrintData.where(pl_plan_key: pl_plan_keys).destroy_all
IdCardPrinterService::CardDataFormatter.new(@employers_member_keys).call
IdCard::PrintData.where(pl_plan_key: pl_plan_keys, primary_mb_member_key: nil).destroy_all
pdf_array = []
batches = break_into_batches(pl_plan_keys)
batches.each do |card_template, batch_pl_plan_keys|
jasper_batch_id = "#{batch_pl_plan_keys.join('_')}-#{Time.current.utc.to_i}"
batch = IdCard::PrintData.where(pl_plan_key: batch_pl_plan_keys)
batch.update!(jasper_batch_id: jasper_batch_id)
batch_pdf = IdCardPrinterService::PdfBatchProcessor.new(card_template, jasper_batch_id, @layout).call
pdf_array << batch_pdf
end
# @employers_member_keys.each do |emk|
# employer_jasper_batches = IdCard::PrintData.where(pl_plan_key: emk[:pl_plan_key]).pluck(:network_logo_id).uniq
# employer_jasper_batches.each do |batch_network_logo|
# jasper_batch_id = "#{emk[:pl_plan_key]}-#{Time.current.utc.to_i}"
# batch = IdCard::PrintData.where(pl_plan_key: emk[:pl_plan_key], network_logo_id: batch_network_logo)
# # batch = employer_card_data.where(network_logo_id: batch_network_logo)
# batch.update!(jasper_batch_id: jasper_batch_id)
# batch_pdf = IdCardPrinterService::PdfBatchProcessor.new(emk[:pl_plan_key], batch_network_logo, jasper_batch_id, @layout).call
# pdf_array << batch_pdf
# end
# end
group_pdfs = combine_pdfs(pdf_array)
group_pdfs
end
private
def break_into_batches(pl_plan_keys)
batches_by_card_template = IdCard::Setup.where(pl_plan_key: pl_plan_keys).group_by(&:card_template)
.transform_values { |setups| setups.map(&:pl_plan_key) }
.compact_blank
end
def combine_pdfs(pdf_array)
if @zip
group_cards_pdf = Zip::OutputStream.write_buffer do |zio|
pdf_array.each do |file|
zio.put_next_entry(file[:name])
zio.write(file[:data])
end
end
else
group_cards_pdf = CombinePDF.new
pdf_array.each { |pdf| group_cards_pdf << pdf }
end
group_cards_pdf
end
end
end
@@ -3,13 +3,36 @@ module IdCardPrinterService
def initialize(employer, layout, zip=false) def initialize(employer, layout, zip=false)
@employer = employer @employer = employer
@member_keys = @employer.members.pluck(:pb_entity_key)
@layout = layout @layout = layout
@zip = zip @zip = zip
end end
def call def call
IdCard::PrintData.where(pl_plan_key: @employer.pl_plan_key).destroy_all IdCard::PrintData.where(pl_plan_key: @employer.pl_plan_key).destroy_all
IdCardPrinterService::EmployerDataFormatter.new(@employer).call IdCardPrinterService::EmployerDataFormatter.new(@employer.pl_plan_key, @member_keys).call
# card_futures.each(&:value)
# max_retries = 60
# retries = 0
# finished = false
# batch_process = BatchProcess.find(batch_id)
# until finished || retries > max_retries
# # Solid Queue stores finished jobs here if preserve_finished_jobs = true
# if batch_process.completed_jobs < batch_process.total_jobs
# sleep 0.5
# retries += 1
# else
# batch_process.destroy!
# finished = true
# end
# end
IdCard::PrintData.where(pl_plan_key: @employer.pl_plan_key, primary_mb_member_key: nil).destroy_all
pdf_array = IdCardPrinterService::PdfProcessor.new(@employer, @layout, @zip).call pdf_array = IdCardPrinterService::PdfProcessor.new(@employer, @layout, @zip).call
@@ -1,37 +1,35 @@
module IdCardPrinterService module IdCardPrinterService
class EmployerDataFormatter class EmployerDataFormatter
def initialize(employer, member_keys = nil) def initialize(pl_plan_key, member_keys)
@employer = employer # @employer = employer
@member_keys = member_keys
@employer = Employer.includes(id_card_setup: [:provider_section, :rx_section]).find_by(pl_plan_key: pl_plan_key)
@card_setup = @employer.id_card_setup @card_setup = @employer.id_card_setup
if member_keys @batch_id
@members = @employer.members.where(pb_entity_key: member_keys).order(:name)
else
@members = @employer.members.order(:name)
end
end end
def call def call
@base_card = IdCard::PrintData.new() # blank_card = IdCard::PrintData.new()
@employer_cards = [] # @employer_cards = []
set_common_fields base_card = initialize_employer_base_card()
set_member_fields create_plan_base_cards(base_card)
card_futures = create_member_cards_async()
set_plan_fields card_futures
@employer_cards.each(&:save!)
end end
private private
def set_common_fields def initialize_employer_base_card
employer_attributes = { employer_attributes = {
pl_plan_key: @card_setup.pl_plan_key, pl_plan_key: @employer.pl_plan_key,
group_number: @employer.group_number, group_number: @employer.group_number,
rx_group: @card_setup.rx_group_number, rx_group: @card_setup.rx_group_number,
network_provider: @card_setup.network_provider network_provider: @card_setup.network_provider
@@ -53,52 +51,70 @@ module IdCardPrinterService
) )
selected_attributes = employer_attributes.merge(rx_attributes).merge(provider_attributes) selected_attributes = employer_attributes.merge(rx_attributes).merge(provider_attributes)
@base_card.assign_attributes(selected_attributes) # blank_card.assign_attributes(selected_attributes)
IdCard::PrintData.new(selected_attributes)
end end
def set_plan_fields def create_plan_base_cards(common_fields_card)
@card_setup.plans.each do |plan| needed_plans_ids = @employer.members.where(pb_entity_key: @member_keys).distinct.pluck(:id_card_plan_id)
selected_attributes = {} needed_plans = @card_setup.plans.where(id: needed_plans_ids)
needed_plans.each do |plan|
selected_attributes = { plan_id: plan.id }
plan.plan_benefits.each do |bene| plan.plan_benefits.each do |bene|
selected_attributes["benefit_desc_#{bene.sequence}".to_sym] = bene.benefit_desc selected_attributes["benefit_desc_#{bene.sequence}".to_sym] = bene.benefit_desc
selected_attributes["benefit_#{bene.sequence}".to_sym] = bene.benefit selected_attributes["benefit_#{bene.sequence}".to_sym] = bene.benefit
end end
@employer_cards.find_all { |card| card.plan_id == plan.id.to_s }.each do |card|
card.assign_attributes(selected_attributes) plan_base_card = common_fields_card.dup
end plan_base_card.assign_attributes(selected_attributes)
plan_base_card.save
end end
end end
def set_member_fields def create_member_cards_async
@group_dependents = Vhcs::VwmbMember.where(pl_plan_key: @employer.pl_plan_key)
@members.each do |me|
effect_date = determine_eff_date(me)
if effect_date
member_card = @base_card.dup
member_attributes = {
full_name: me.id_card_display_name,
full_name_last_name_first: me.name,
primary_mb_member_key: me.pb_entity_key,
family_id: me.family_id,
plan_id: me.id_card_plan_id,
medical_eff_date: effect_date.strftime("%m/%d/%Y")
}
if @card_setup.has_divisions mmember_card_futures = @member_keys.map do |member_key|
member_attributes.merge!({employer_name: me.division}) Concurrent::Future.execute do
ActiveRecord::Base.connection_pool.with_connection do
ProcessIdCardDataJob.perform_now(member_key, @card_setup.has_divisions)
end end
dependent_attributes = get_dependent_fields(me)
if dependent_attributes.present?
selected_attributes = member_attributes.merge(dependent_attributes)
else
selected_attributes = member_attributes
end
member_card.assign_attributes(selected_attributes)
@employer_cards.push(member_card)
end end
end end
mmember_card_futures
# batch_process = BatchProcess.create!(total_jobs: @member_keys.count)
# @member_keys.each do |member_key|
# ProcessIdCardDataJob.perform_later(member_key, @card_setup.has_divisions, batch_process.id)
# end
# @batch_id = batch_process.id
# @members.each do |me|
# effect_date = determine_eff_date(me)
# if effect_date
# member_card = @base_card.dup
# member_attributes = {
# full_name: me.id_card_display_name,
# full_name_last_name_first: me.name,
# primary_mb_member_key: me.pb_entity_key,
# family_id: me.family_id,
# plan_id: me.id_card_plan_id,
# medical_eff_date: effect_date.strftime("%m/%d/%Y")
# }
# if @card_setup.has_divisions
# member_attributes.merge!({employer_name: me.division})
# end
# dependent_attributes = get_dependent_fields(me)
# if dependent_attributes.present?
# selected_attributes = member_attributes.merge(dependent_attributes)
# else
# selected_attributes = member_attributes
# end
# member_card.assign_attributes(selected_attributes)
# @employer_cards.push(member_card)
# end
# end
end end
# def set_network_fields # def set_network_fields
@@ -0,0 +1,40 @@
module IdCardPrinterService
class JasperBatchUrlGenerator
def initialize(card_template, jasper_batch_id, layout)
@card_template = card_template
@jasper_batch_id = jasper_batch_id
@layout = layout
end
def call
URI::HTTP.build(url_components)
end
private
# def determine_network_logo
# # if @network_logos.length > 1
# # member_geographic_info = Vhcs::PbEntityAddress.joins("INNER JOIN vwMBMember ON PBEntityAddress.PBEntityKey = vwMBMember.PBEntityKey AND PBEntityAddress.AddressTypeID = 1137").where("vwMBMember.FamilyID = ?", @family_id).first
# # @network_logos.where.not(default: true).each do |pnl|
# # if member_geographic_info[pnl.exception_type] == pnl.exception_value
# # return pnl.net_logo
# # end
# # end
# # end
# # @network_logos.find_by(default: true).net_logo
# IdCard::NetworkLogo.find(@network_logo_id).filename
# end
# http://localhost:8080/trunk/PdfServlet?reportConn=BrittonConnect&id=&reportName=FairosRxSampleIDCard-Half&family_id=Classic%202K&employer_logo=BryanPestControl.jpeg&network_logo=CignaLogo.png&reportDir=secure/Documents&SUBREPORT_DIR=/&ImageDir=secure/Documents&netToken=3a4a8b03f4dfb0e6e3fc82dd369f70ef&FileType=PDF
# http://localhost:8080/trunk/PdfServlet?reportConn=BrittonConnect&id=&reportName=FairosRxSampleIDCard-Half&family_id=Classic%202K&employer_logo=BryanPestControl.jpeg&network_logo=CignaLogo.png&reportDir=secure/Documents&SUBREPORT_DIR=/&ImageDir=secure/Documents&netToken=3a4a8b03f4dfb0e6e3fc82dd369f70ef&FileType=PDF
def url_components
{
host: '10.41.1.115',
port: 8080,
path: '/trunk/IdCardsServlet',
query: "reportConn=BrittonConnect&cardTemplate=#{@card_template}Batch&printType=Batch#{@layout}&jasper_batch_id=#{@jasper_batch_id}&FileType=PDF"
}
end
end
end
@@ -0,0 +1,36 @@
module IdCardPrinterService
class PdfBatchProcessor
def initialize(card_template, jasper_batch_id, layout)
@card_template = card_template
@jasper_batch_id = jasper_batch_id
@layout = layout
end
def call
# if @zip
# group_cards_pdf_array = []
# else
# group_cards_pdf = CombinePDF.new
# end
url = IdCardPrinterService::JasperBatchUrlGenerator.new(@card_template, @jasper_batch_id, @layout).call
puts url
batch_pdf = IdCardPrinterService::JasperPdfGenerator.new(url).call
# if @zip
# group_cards_pdf = Zip::OutputStream.write_buffer do |zio|
# group_cards_pdf_array.each do |file|
# zio.put_next_entry(file[:name])
# zio.write(file[:data])
# end
# end
# # else
# # todays_date = DateTime.current.strftime('%Y%m%d%H%M%S')
# # group_cards_pdf.save("tmp/#{@employer.name}_print_cards_#{todays_date}.pdf")
# end
batch_pdf
end
end
end
@@ -3,7 +3,6 @@ module IdCardPrinterService
def initialize(employer, layout, zip = false) def initialize(employer, layout, zip = false)
@employer = employer @employer = employer
@card_setup = @employer.id_card_setup
@layout = layout @layout = layout
@zip = zip @zip = zip
end end
@@ -6,7 +6,7 @@ module IdCardPrinterService
end end
def call def call
IdCard::PrintData.where(employer_name: @employer.name).destroy_all IdCard::PrintData.where(employer_name: @employer.id_card_setup.print_name).destroy_all
IdCardPrinterService::SampleDataFormatter.new(@employer).call IdCardPrinterService::SampleDataFormatter.new(@employer).call
IdCardPrinterService::SamplePdfProcessor.new(@employer).call IdCardPrinterService::SamplePdfProcessor.new(@employer).call
@@ -23,7 +23,7 @@ module IdCardPrinterService
def set_employer_fields def set_employer_fields
selected_attributes = { selected_attributes = {
employer_name: @employer.name, employer_name: @card_setup.print_name,
group_number: @employer.group_number.present? ? @employer.group_number : "999999", group_number: @employer.group_number.present? ? @employer.group_number : "999999",
medical_eff_date: @employer.effective_date medical_eff_date: @employer.effective_date
} }
@@ -8,7 +8,7 @@ module IdCardPrinterService
def call def call
group_cards_pdf = CombinePDF.new group_cards_pdf = CombinePDF.new
IdCard::PrintData.where(employer_name: @employer.name).each do |card| IdCard::PrintData.where(employer_name: @card_setup.print_name).each do |card|
url = IdCardPrinterService::SampleJasperUrlGenerator.new(@employer, card.sample_key, card.sample_plan_title).call url = IdCardPrinterService::SampleJasperUrlGenerator.new(@employer, card.sample_key, card.sample_plan_title).call
puts url puts url
card_pdf = IdCardPrinterService::JasperPdfGenerator.new(url).call card_pdf = IdCardPrinterService::JasperPdfGenerator.new(url).call
@@ -10,7 +10,21 @@ module IdCardQueueService
end end
def call def call
CallStoredProc.new('BrittonGetQueuedIdCardMemberKeysTPA', { PLPlanKeys: @employer_pl_plan_keys }).call.to_ary raw_employers_member_keys = CallStoredProc.new('BrittonGetQueuedIdCardMemberKeysTPA', { PLPlanKeys: @employer_pl_plan_keys }).call.to_ary
format_employers_member_keys(raw_employers_member_keys)
end
private
def format_employers_member_keys(raw_employers_member_keys)
key_map = { "PlanKey" => :pl_plan_key, "MemberKeys" => :member_keys }
raw_employers_member_keys.map do |hash|
hash["PlanKey"] = hash["PlanKey"].to_s
hash["MemberKeys"] = hash["MemberKeys"].split(", ").map(&:to_i)
hash.transform_keys(key_map)
end
end end
end end
+6
View File
@@ -0,0 +1,6 @@
#!/usr/bin/env ruby
require_relative "../config/environment"
require "solid_queue/cli"
SolidQueue::Cli.start(ARGV)
+1
View File
@@ -40,5 +40,6 @@ module Baclight
# Don't generate system test files. # Don't generate system test files.
config.generators.system_tests = nil config.generators.system_tests = nil
config.active_job.queue_adapter = :solid_queue
end end
end end
+4
View File
@@ -81,4 +81,8 @@ Rails.application.configure do
# Apply autocorrection by RuboCop to files generated by `bin/rails generate`. # Apply autocorrection by RuboCop to files generated by `bin/rails generate`.
# config.generators.apply_rubocop_autocorrect_after_generate! # config.generators.apply_rubocop_autocorrect_after_generate!
config.active_job.queue_adapter = :solid_queue
config.solid_queue.connects_to = { database: { writing: :baclight } }
# config.active_job.queue_adapter = :async
end end
+3 -1
View File
@@ -71,7 +71,9 @@ Rails.application.configure do
# config.cache_store = :mem_cache_store # config.cache_store = :mem_cache_store
# Use a real queuing backend for Active Job (and separate queues per environment). # Use a real queuing backend for Active Job (and separate queues per environment).
# config.active_job.queue_adapter = :resque config.active_job.queue_adapter = :solid_queue
# config.solid_queue.connects_to = { database: { writing: :queue } }
# config.solid_queue.connects_to = { database: { writing: :queue } }
# config.active_job.queue_name_prefix = "railsondocker_production" # config.active_job.queue_name_prefix = "railsondocker_production"
# Disable caching for Action Mailer templates even if Action Controller # Disable caching for Action Mailer templates even if Action Controller
+2
View File
@@ -29,6 +29,8 @@ port ENV.fetch("PORT", 3002)
# Allow puma to be restarted by `bin/rails restart` command. # Allow puma to be restarted by `bin/rails restart` command.
plugin :tmp_restart plugin :tmp_restart
plugin :solid_queue if Rails.env.development?
# plugin :tailwindcss # plugin :tailwindcss
# Only use a pidfile when requested # Only use a pidfile when requested
+18
View File
@@ -0,0 +1,18 @@
default: &default
dispatchers:
- polling_interval: 1
batch_size: 500
workers:
- queues: "*"
threads: 3
processes: <%= ENV.fetch("JOB_CONCURRENCY", 1) %>
polling_interval: 0.1
development:
<<: *default
test:
<<: *default
production:
<<: *default
+15
View File
@@ -0,0 +1,15 @@
# examples:
# periodic_cleanup:
# class: CleanSoftDeletedRecordsJob
# queue: background
# args: [ 1000, { batch_size: 500 } ]
# schedule: every hour
# periodic_cleanup_with_command:
# command: "SoftDeletedRecord.due.delete_all"
# priority: 2
# schedule: at 5am every day
production:
clear_solid_queue_finished_jobs:
command: "SolidQueue::Job.clear_finished_in_batches(sleep_between_batches: 0.3)"
schedule: every hour at minute 12
@@ -74,9 +74,13 @@ class CreateIdCardPrintData < ActiveRecord::Migration[7.0]
t.string :benefit_13 t.string :benefit_13
t.string :benefit_desc_14 t.string :benefit_desc_14
t.string :benefit_14 t.string :benefit_14
t.integer :network_logo_id
t.string :network_logo_filename
t.string :employer_logo_filename
t.boolean :sample, default: false t.boolean :sample, default: false
t.string :sample_key t.string :sample_key
t.string :sample_plan_title t.string :sample_plan_title
t.string :jasper_batch_id
t.timestamps t.timestamps
end end
@@ -0,0 +1,131 @@
class SolidQueueSetup < ActiveRecord::Migration[7.2]
def change
create_table "solid_queue_blocked_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.string "concurrency_key", null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.index [ "concurrency_key", "priority", "job_id" ], name: "index_solid_queue_blocked_executions_for_release"
t.index [ "expires_at", "concurrency_key" ], name: "index_solid_queue_blocked_executions_for_maintenance"
t.index [ "job_id" ], name: "index_solid_queue_blocked_executions_on_job_id", unique: true
end
create_table "solid_queue_claimed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.bigint "process_id"
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_claimed_executions_on_job_id", unique: true
t.index [ "process_id", "job_id" ], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id"
end
create_table "solid_queue_failed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.text "error"
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_failed_executions_on_job_id", unique: true
end
create_table "solid_queue_jobs", force: :cascade do |t|
t.string "queue_name", null: false
t.string "class_name", null: false
t.text "arguments"
t.integer "priority", default: 0, null: false
t.string "active_job_id"
t.datetime "scheduled_at"
t.datetime "finished_at"
t.string "concurrency_key"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index [ "active_job_id" ], name: "index_solid_queue_jobs_on_active_job_id"
t.index [ "class_name" ], name: "index_solid_queue_jobs_on_class_name"
t.index [ "finished_at" ], name: "index_solid_queue_jobs_on_finished_at"
t.index [ "queue_name", "finished_at" ], name: "index_solid_queue_jobs_for_filtering"
t.index [ "scheduled_at", "finished_at" ], name: "index_solid_queue_jobs_for_alerting"
end
create_table "solid_queue_pauses", force: :cascade do |t|
t.string "queue_name", null: false
t.datetime "created_at", null: false
t.index [ "queue_name" ], name: "index_solid_queue_pauses_on_queue_name", unique: true
end
create_table "solid_queue_processes", force: :cascade do |t|
t.string "kind", null: false
t.datetime "last_heartbeat_at", null: false
t.bigint "supervisor_id"
t.integer "pid", null: false
t.string "hostname"
t.text "metadata"
t.datetime "created_at", null: false
t.string "name", null: false
t.index [ "last_heartbeat_at" ], name: "index_solid_queue_processes_on_last_heartbeat_at"
t.index [ "name", "supervisor_id" ], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true
t.index [ "supervisor_id" ], name: "index_solid_queue_processes_on_supervisor_id"
end
create_table "solid_queue_ready_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_ready_executions_on_job_id", unique: true
t.index [ "priority", "job_id" ], name: "index_solid_queue_poll_all"
t.index [ "queue_name", "priority", "job_id" ], name: "index_solid_queue_poll_by_queue"
end
create_table "solid_queue_recurring_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "task_key", null: false
t.datetime "run_at", null: false
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_recurring_executions_on_job_id", unique: true
t.index [ "task_key", "run_at" ], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true
end
create_table "solid_queue_recurring_tasks", force: :cascade do |t|
t.string "key", null: false
t.string "schedule", null: false
t.string "command", limit: 2048
t.string "class_name"
t.text "arguments"
t.string "queue_name"
t.integer "priority", default: 0
t.boolean "static", default: true, null: false
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index [ "key" ], name: "index_solid_queue_recurring_tasks_on_key", unique: true
t.index [ "static" ], name: "index_solid_queue_recurring_tasks_on_static"
end
create_table "solid_queue_scheduled_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "scheduled_at", null: false
t.datetime "created_at", null: false
t.index [ "job_id" ], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true
t.index [ "scheduled_at", "priority", "job_id" ], name: "index_solid_queue_dispatch_all"
end
create_table "solid_queue_semaphores", force: :cascade do |t|
t.string "key", null: false
t.integer "value", default: 1, null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index [ "expires_at" ], name: "index_solid_queue_semaphores_on_expires_at"
t.index [ "key", "value" ], name: "index_solid_queue_semaphores_on_key_and_value"
t.index [ "key" ], name: "index_solid_queue_semaphores_on_key", unique: true
end
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
end
end
+132 -1
View File
@@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.2].define(version: 2026_01_16_182836) do ActiveRecord::Schema[7.2].define(version: 2026_03_20_152726) do
create_table "employers", force: :cascade do |t| create_table "employers", force: :cascade do |t|
t.string "name" t.string "name"
t.string "slug" t.string "slug"
@@ -162,9 +162,13 @@ ActiveRecord::Schema[7.2].define(version: 2026_01_16_182836) do
t.string "benefit_13" t.string "benefit_13"
t.string "benefit_desc_14" t.string "benefit_desc_14"
t.string "benefit_14" t.string "benefit_14"
t.integer "network_logo_id"
t.string "network_logo_filename"
t.string "employer_logo_filename"
t.boolean "sample", default: false t.boolean "sample", default: false
t.string "sample_key" t.string "sample_key"
t.string "sample_plan_title" t.string "sample_plan_title"
t.string "jasper_batch_id"
t.datetime "created_at", null: false t.datetime "created_at", null: false
t.datetime "updated_at", null: false t.datetime "updated_at", null: false
end end
@@ -265,6 +269,127 @@ ActiveRecord::Schema[7.2].define(version: 2026_01_16_182836) do
t.index ["id_card_plan_id"], name: "index_members_on_id_card_plan_id" t.index ["id_card_plan_id"], name: "index_members_on_id_card_plan_id"
end end
create_table "solid_queue_blocked_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.string "concurrency_key", null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.index ["concurrency_key", "priority", "job_id"], name: "index_solid_queue_blocked_executions_for_release"
t.index ["expires_at", "concurrency_key"], name: "index_solid_queue_blocked_executions_for_maintenance"
t.index ["job_id"], name: "index_solid_queue_blocked_executions_on_job_id", unique: true
end
create_table "solid_queue_claimed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.bigint "process_id"
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_claimed_executions_on_job_id", unique: true
t.index ["process_id", "job_id"], name: "index_solid_queue_claimed_executions_on_process_id_and_job_id"
end
create_table "solid_queue_failed_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.text "error"
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_failed_executions_on_job_id", unique: true
end
create_table "solid_queue_jobs", force: :cascade do |t|
t.string "queue_name", null: false
t.string "class_name", null: false
t.text "arguments"
t.integer "priority", default: 0, null: false
t.string "active_job_id"
t.datetime "scheduled_at"
t.datetime "finished_at"
t.string "concurrency_key"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["active_job_id"], name: "index_solid_queue_jobs_on_active_job_id"
t.index ["class_name"], name: "index_solid_queue_jobs_on_class_name"
t.index ["finished_at"], name: "index_solid_queue_jobs_on_finished_at"
t.index ["queue_name", "finished_at"], name: "index_solid_queue_jobs_for_filtering"
t.index ["scheduled_at", "finished_at"], name: "index_solid_queue_jobs_for_alerting"
end
create_table "solid_queue_pauses", force: :cascade do |t|
t.string "queue_name", null: false
t.datetime "created_at", null: false
t.index ["queue_name"], name: "index_solid_queue_pauses_on_queue_name", unique: true
end
create_table "solid_queue_processes", force: :cascade do |t|
t.string "kind", null: false
t.datetime "last_heartbeat_at", null: false
t.bigint "supervisor_id"
t.integer "pid", null: false
t.string "hostname"
t.text "metadata"
t.datetime "created_at", null: false
t.string "name", null: false
t.index ["last_heartbeat_at"], name: "index_solid_queue_processes_on_last_heartbeat_at"
t.index ["name", "supervisor_id"], name: "index_solid_queue_processes_on_name_and_supervisor_id", unique: true
t.index ["supervisor_id"], name: "index_solid_queue_processes_on_supervisor_id"
end
create_table "solid_queue_ready_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_ready_executions_on_job_id", unique: true
t.index ["priority", "job_id"], name: "index_solid_queue_poll_all"
t.index ["queue_name", "priority", "job_id"], name: "index_solid_queue_poll_by_queue"
end
create_table "solid_queue_recurring_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "task_key", null: false
t.datetime "run_at", null: false
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_recurring_executions_on_job_id", unique: true
t.index ["task_key", "run_at"], name: "index_solid_queue_recurring_executions_on_task_key_and_run_at", unique: true
end
create_table "solid_queue_recurring_tasks", force: :cascade do |t|
t.string "key", null: false
t.string "schedule", null: false
t.string "command", limit: 2048
t.string "class_name"
t.text "arguments"
t.string "queue_name"
t.integer "priority", default: 0
t.boolean "static", default: true, null: false
t.text "description"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["key"], name: "index_solid_queue_recurring_tasks_on_key", unique: true
t.index ["static"], name: "index_solid_queue_recurring_tasks_on_static"
end
create_table "solid_queue_scheduled_executions", force: :cascade do |t|
t.bigint "job_id", null: false
t.string "queue_name", null: false
t.integer "priority", default: 0, null: false
t.datetime "scheduled_at", null: false
t.datetime "created_at", null: false
t.index ["job_id"], name: "index_solid_queue_scheduled_executions_on_job_id", unique: true
t.index ["scheduled_at", "priority", "job_id"], name: "index_solid_queue_dispatch_all"
end
create_table "solid_queue_semaphores", force: :cascade do |t|
t.string "key", null: false
t.integer "value", default: 1, null: false
t.datetime "expires_at", null: false
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["expires_at"], name: "index_solid_queue_semaphores_on_expires_at"
t.index ["key", "value"], name: "index_solid_queue_semaphores_on_key_and_value"
t.index ["key"], name: "index_solid_queue_semaphores_on_key", unique: true
end
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_field_exceptions", column: "field_exception_id"
add_foreign_key "id_card_field_exception_items", "id_card_network_logos", column: "network_logo_id" add_foreign_key "id_card_field_exception_items", "id_card_network_logos", column: "network_logo_id"
add_foreign_key "id_card_field_exception_items", "id_card_provider_sections", column: "provider_section_id" add_foreign_key "id_card_field_exception_items", "id_card_provider_sections", column: "provider_section_id"
@@ -278,4 +403,10 @@ ActiveRecord::Schema[7.2].define(version: 2026_01_16_182836) do
add_foreign_key "id_card_setups", "id_card_rx_sections", column: "rx_section_id" add_foreign_key "id_card_setups", "id_card_rx_sections", column: "rx_section_id"
add_foreign_key "members", "employers" add_foreign_key "members", "employers"
add_foreign_key "members", "id_card_plans" add_foreign_key "members", "id_card_plans"
add_foreign_key "solid_queue_blocked_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_claimed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_failed_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_ready_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_recurring_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
add_foreign_key "solid_queue_scheduled_executions", "solid_queue_jobs", column: "job_id", on_delete: :cascade
end end
+15 -2
View File
@@ -1,7 +1,7 @@
# ----- Build Stage ----- # ----- Build Stage -----
# Using a specific Ruby version (e.g., 3.3) for stability # Using a specific Ruby version (e.g., 3.3) for stability
ARG RUBY_VERSION=3.4.8 ARG RUBY_VERSION=3.4.8
FROM docker.io/library/ruby:$RUBY_VERSION-slim as base FROM docker.io/library/ruby:3.4.8-slim as base
# Install production system dependencies # Install production system dependencies
RUN --mount=type=cache,target=/var/cache/apt \ RUN --mount=type=cache,target=/var/cache/apt \
@@ -27,6 +27,8 @@ WORKDIR /usr/src/app
RUN gem install foreman RUN gem install foreman
# RUN chmod +x /usr/src/app/bin/jobs
# Copy runtime Ruby dependencies and the precompiled assets from the builder stage # 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/local/bundle /usr/local/bundle
# COPY --from=builder /usr/src/app /usr/src/app # COPY --from=builder /usr/src/app /usr/src/app
@@ -37,6 +39,17 @@ RUN gem install foreman
# && touch /usr/local/var/run/watchman/.not-empty \ # && touch /usr/local/var/run/watchman/.not-empty \
# && chmod 2777 /usr/local/var/run/watchman # && chmod 2777 /usr/local/var/run/watchman
# COPY . .
# 1. Add bin/jobs script to container
COPY bin/jobs /usr/src/bin/jobs
# 2. Make the script executable
RUN chmod +x /usr/src/bin/jobs
# 3. Set it as the entrypoint
# ENTRYPOINT ["/usr/src/bin/jobs"]
# The entrypoint script is a good practice for handling Rails server startup # The entrypoint script is a good practice for handling Rails server startup
ENTRYPOINT ["./bin/docker-entrypoint-development"] ENTRYPOINT ["./bin/docker-entrypoint-development"]
@@ -44,4 +57,4 @@ ENTRYPOINT ["./bin/docker-entrypoint-development"]
EXPOSE 3002 EXPOSE 3002
# Set the default command to run the Rails server # Set the default command to run the Rails server
CMD ["./bin/dev"] CMD ["./bin/dev", "bin/jobs start"]