Skip to content

Commit c30771c

Browse files
authored
Add section headers to PDF overflow page (#20894)
* Add section headers to PDF overflow page * Fix rubocop complaints * Fix test regressions * Consolidate calculation of section index * Add unit test for HashConverter top_level_key logic * Add new test for sorting questions by section index * Fix rubocop complaints * Add new test for populate_section_indices * Revert some unnecessary reformatting * Nevermind, collapse this call after all for method length
1 parent 1093838 commit c30771c

File tree

8 files changed

+197
-53
lines changed

8 files changed

+197
-53
lines changed

lib/pdf_fill/extras_generator.rb

+29-2
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,12 @@ module PdfFill
44
class ExtrasGenerator
55
attr_reader :extras_redesign
66

7-
def initialize(form_name: nil, extras_redesign: false, start_page: 1)
7+
def initialize(extras_redesign: false, form_name: nil, start_page: 1, sections: nil)
88
@generate_blocks = []
99
@form_name = form_name
1010
@extras_redesign = extras_redesign
1111
@start_page = start_page
12+
@sections = sections
1213
end
1314

1415
def create_block(value, metadata)
@@ -26,7 +27,7 @@ def create_block(value, metadata)
2627
end
2728

2829
def add_text(value, metadata)
29-
unless text?
30+
unless text? || extras_redesign
3031
@generate_blocks << {
3132
metadata: {},
3233
block: lambda do |pdf|
@@ -45,10 +46,22 @@ def text?
4546
@generate_blocks.size.positive?
4647
end
4748

49+
def populate_section_indices!
50+
return if @sections.blank?
51+
52+
@generate_blocks.each do |generate_block|
53+
metadata = generate_block[:metadata]
54+
if metadata[:top_level_key].present?
55+
metadata[:section_index] = @sections.index { |sec| sec[:top_level_keys].include?(metadata[:top_level_key]) }
56+
end
57+
end
58+
end
59+
4860
def sort_generate_blocks
4961
@generate_blocks.sort_by do |generate_block|
5062
metadata = generate_block[:metadata]
5163
[
64+
metadata[:section_index] || -1,
5265
metadata[:question_num] || -1,
5366
metadata[:i] || 99_999,
5467
metadata[:question_suffix] || '',
@@ -101,14 +114,27 @@ def generate_pdf(file_path, generate_blocks)
101114
end
102115
end
103116

117+
def render_new_section(pdf, section_index)
118+
return unless @extras_redesign && @sections.present?
119+
120+
pdf.move_down(20)
121+
pdf.text(@sections[section_index][:label], { size: 14 })
122+
end
123+
104124
def render_pdf_content(pdf, generate_blocks)
125+
current_section_index = nil
105126
box_height = 25
106127
pdf.bounding_box(
107128
[pdf.bounds.left, pdf.bounds.top - box_height],
108129
width: pdf.bounds.width,
109130
height: pdf.bounds.height - box_height
110131
) do
111132
generate_blocks.each do |block|
133+
section_index = block[:metadata][:section_index]
134+
if section_index.present? && section_index != current_section_index
135+
render_new_section(pdf, section_index)
136+
current_section_index = section_index
137+
end
112138
block[:block].call(pdf)
113139
end
114140
end
@@ -118,6 +144,7 @@ def generate
118144
folder = 'tmp/pdfs'
119145
FileUtils.mkdir_p(folder)
120146
file_path = "#{folder}/extras_#{SecureRandom.uuid}.pdf"
147+
populate_section_indices!
121148
generate_blocks = sort_generate_blocks
122149
generate_pdf(file_path, generate_blocks)
123150
file_path

lib/pdf_fill/filler.rb

+7-8
Original file line numberDiff line numberDiff line change
@@ -138,10 +138,12 @@ def process_form(form_id, form_data, form_class, file_name_extension, fill_optio
138138
folder = 'tmp/pdfs'
139139
FileUtils.mkdir_p(folder)
140140
file_path = "#{folder}/#{form_id}_#{file_name_extension}.pdf"
141-
start_page = form_class.const_defined?(:START_PAGE) ? form_class::START_PAGE : 1
142-
hash_converter = HashConverter.new(form_id.sub(/V2\z/, ''), form_class.date_strftime,
143-
fill_options.fetch(:extras_redesign, false), start_page)
144-
141+
extras_generator = ExtrasGenerator.new(
142+
extras_redesign: fill_options.fetch(:extras_redesign, false),
143+
form_name: form_id.sub(/V2\z/, ''),
144+
start_page: form_class::START_PAGE, sections: form_class::SECTIONS
145+
)
146+
hash_converter = HashConverter.new(form_class.date_strftime, extras_generator)
145147
new_hash = hash_converter.transform_data(
146148
form_data: form_class.new(form_data).merge_fields(fill_options),
147149
pdftk_keys: form_class::KEY
@@ -151,10 +153,7 @@ def process_form(form_id, form_data, form_class, file_name_extension, fill_optio
151153
template_path = has_template ? form_class::TEMPLATE : "lib/pdf_fill/forms/pdfs/#{form_id}.pdf"
152154

153155
(form_id == SavedClaim::CaregiversAssistanceClaim::FORM ? UNICODE_PDF_FORMS : PDF_FORMS).fill_form(
154-
template_path,
155-
file_path,
156-
new_hash,
157-
flatten: Rails.env.production?
156+
template_path, file_path, new_hash, flatten: Rails.env.production?
158157
)
159158

160159
combine_extras(file_path, hash_converter.extras_generator)

lib/pdf_fill/forms/form_base.rb

+3
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ module Forms
77
class FormBase
88
attr_reader :form_data
99

10+
START_PAGE = 1
11+
SECTIONS = nil
12+
1013
def self.date_strftime
1114
'%m/%d/%Y'
1215
end

lib/pdf_fill/forms/va210781v2.rb

+30
Original file line numberDiff line numberDiff line change
@@ -615,6 +615,36 @@ class Va210781v2 < FormBase
615615
}.freeze
616616
# rubocop:enable Layout/LineLength
617617

618+
SECTIONS = [
619+
{
620+
label: 'Section I: Veteran\'s Identification Information',
621+
top_level_keys: %w[
622+
veteranFullName vaFileNumber veteranDateOfBirth veteranServiceNumber veteranPhone veteranIntPhone
623+
email emailOverflow
624+
]
625+
},
626+
{
627+
label: 'Section II: Traumatic Event(s) Information',
628+
top_level_keys: ['events']
629+
},
630+
{
631+
label: 'Section III: Additional Information Associated with the In-service Traumatic Event(s)',
632+
top_level_keys: %w[workBehaviors healthBehaviors otherBehaviors behaviorsDetails reportsDetails evidence]
633+
},
634+
{
635+
label: 'Section IV: Treatment Information',
636+
top_level_keys: ['treatmentProvidersDetails']
637+
},
638+
{
639+
label: 'Section V: Remarks',
640+
top_level_keys: %w[additionalInformation additionalInformationOverflow]
641+
},
642+
{
643+
label: 'Section VII: Certification and Signature',
644+
top_level_keys: %w[signature signatureDate]
645+
}
646+
].freeze
647+
618648
def merge_fields(_options = {})
619649
@form_data['veteranFullName'] = extract_middle_i(@form_data, 'veteranFullName')
620650
@form_data = expand_ssn(@form_data)

lib/pdf_fill/hash_converter.rb

+19-17
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ class HashConverter
1111

1212
attr_reader :extras_generator
1313

14-
def initialize(form_name, date_strftime, extras_redesign = false, start_page = 1)
14+
def initialize(date_strftime, extras_generator)
1515
@pdftk_form = {}
1616
@date_strftime = date_strftime
17-
@extras_generator = ExtrasGenerator.new(form_name:, extras_redesign:, start_page:)
17+
@extras_generator = extras_generator
1818
end
1919

2020
def convert_value(v, key_data, is_overflow = false)
@@ -63,7 +63,7 @@ def overflow?(key_data, value, from_array_overflow = false)
6363
limit.present? && value.size > limit
6464
end
6565

66-
def add_to_extras(key_data, v, i)
66+
def add_to_extras(key_data, v, i, top_level_key)
6767
return if v.blank?
6868
return if key_data.try(:[], :question_text).blank?
6969

@@ -73,25 +73,25 @@ def add_to_extras(key_data, v, i)
7373
@extras_generator.add_text(
7474
v,
7575
key_data.slice(:question_num, :question_suffix, :question_text).merge(
76-
i:
76+
i:, top_level_key:
7777
)
7878
)
7979
end
8080

81-
def add_array_to_extras(arr, pdftk_keys)
81+
def add_array_to_extras(arr, pdftk_keys, top_level_key)
8282
arr.each_with_index do |v, i|
8383
i = nil if pdftk_keys[:always_overflow]
8484
if v.is_a?(Hash)
8585
v.each do |key, val|
86-
add_to_extras(pdftk_keys[key], convert_value(val, pdftk_keys[key], true), i)
86+
add_to_extras(pdftk_keys[key], convert_value(val, pdftk_keys[key], true), i, top_level_key)
8787
end
8888
else
89-
add_to_extras(pdftk_keys, convert_value(v, pdftk_keys, true), i)
89+
add_to_extras(pdftk_keys, convert_value(v, pdftk_keys, true), i, top_level_key)
9090
end
9191
end
9292
end
9393

94-
def set_value(v, key_data, i, from_array_overflow = false)
94+
def set_value(v, key_data, i, from_array_overflow = false, top_level_key = nil)
9595
k = key_data[:key]
9696
return if k.blank?
9797

@@ -100,7 +100,7 @@ def set_value(v, key_data, i, from_array_overflow = false)
100100
new_value = convert_value(v, key_data)
101101

102102
if overflow?(key_data, new_value, from_array_overflow)
103-
add_to_extras(key_data, new_value, i)
103+
add_to_extras(key_data, new_value, i, top_level_key)
104104

105105
new_value = EXTRAS_TEXT
106106
end
@@ -123,7 +123,7 @@ def check_for_overflow(arr, pdftk_keys)
123123
false
124124
end
125125

126-
def transform_array(form_data, pdftk_keys)
126+
def transform_array(form_data, pdftk_keys, top_level_key)
127127
has_overflow = check_for_overflow(form_data, pdftk_keys)
128128

129129
if has_overflow
@@ -133,34 +133,36 @@ def transform_array(form_data, pdftk_keys)
133133
form_data: { first_key => EXTRAS_TEXT },
134134
pdftk_keys:,
135135
i: 0,
136-
from_array_overflow: true
136+
from_array_overflow: true,
137+
top_level_key:
137138
)
138139

139-
add_array_to_extras(form_data, pdftk_keys)
140+
add_array_to_extras(form_data, pdftk_keys, top_level_key)
140141
else
141142
form_data.each_with_index do |v, idx|
142-
transform_data(form_data: v, pdftk_keys:, i: idx)
143+
transform_data(form_data: v, pdftk_keys:, i: idx, top_level_key:)
143144
end
144145
end
145146
end
146147

147-
def transform_data(form_data:, pdftk_keys:, i: nil, from_array_overflow: false)
148+
def transform_data(form_data:, pdftk_keys:, i: nil, from_array_overflow: false, top_level_key: nil)
148149
return if form_data.nil? || pdftk_keys.nil?
149150

150151
case form_data
151152
when Array
152-
transform_array(form_data, pdftk_keys)
153+
transform_array(form_data, pdftk_keys, top_level_key)
153154
when Hash
154155
form_data.each do |k, v|
155156
transform_data(
156157
form_data: v,
157158
pdftk_keys: pdftk_keys[k],
158159
i:,
159-
from_array_overflow:
160+
from_array_overflow:,
161+
top_level_key: top_level_key || k
160162
)
161163
end
162164
else
163-
set_value(form_data, pdftk_keys, i, from_array_overflow)
165+
set_value(form_data, pdftk_keys, i, from_array_overflow, top_level_key)
164166
end
165167

166168
@pdftk_form
Binary file not shown.

spec/lib/pdf_fill/extras_generator_spec.rb

+51-4
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,38 @@
44
require 'pdf_fill/extras_generator'
55

66
describe PdfFill::ExtrasGenerator do
7-
subject do
8-
described_class.new
7+
subject { described_class.new(sections:) }
8+
9+
let(:sections) { nil }
10+
11+
describe '#populate_section_indices!' do
12+
let(:sections) do
13+
[
14+
{
15+
label: 'Section I',
16+
top_level_keys: %w[veteranFullName vaFileNumber veteranDateOfBirth]
17+
},
18+
{
19+
label: 'Section II',
20+
top_level_keys: ['events']
21+
}
22+
]
23+
end
24+
25+
it 'populates section indices correctly' do
26+
blocks = %w[veteranFullName events evidence vaFileNumber].map do |top_level_key|
27+
{ metadata: { top_level_key: } }
28+
end
29+
subject.instance_variable_set(:@generate_blocks, blocks)
30+
subject.populate_section_indices!
31+
indices = subject.instance_variable_get(:@generate_blocks).map { |block| block[:metadata][:section_index] }
32+
expect(indices).to eq([0, 1, nil, 0])
33+
end
934
end
1035

1136
describe '#sort_generate_blocks' do
12-
it 'sorts the blocks correctly' do
13-
metadatas = [
37+
let(:metadatas) do
38+
[
1439
{
1540
question_num: 1
1641
},
@@ -41,7 +66,9 @@
4166
question_suffix: 'B'
4267
}
4368
]
69+
end
4470

71+
it 'sorts the blocks correctly' do
4572
subject.instance_variable_set(:@generate_blocks, metadatas.reverse.map do |metadata|
4673
{
4774
metadata:
@@ -52,6 +79,26 @@
5279
expect(generate_block[:metadata]).to eq(metadatas[i])
5380
end
5481
end
82+
83+
context 'when section metadata is provided' do
84+
let(:metadatas) do
85+
[
86+
{ section_index: 0, question_num: 2, question_suffix: 'A', question_text: 'First Name' },
87+
{ section_index: 0, question_num: 2, question_suffix: 'B', question_text: 'Last Name' },
88+
{ section_index: 0, question_num: 3, question_text: 'Email Address' },
89+
{ section_index: 1, question_num: 1, question_text: 'Remarks' },
90+
{ section_index: 1, question_num: 4, question_text: 'Additional Remarks' }
91+
]
92+
end
93+
94+
it 'sorts the blocks correctly, even if question numbers are jumbled' do
95+
subject.instance_variable_set(:@generate_blocks, metadatas.reverse.map { |metadata| { metadata: } })
96+
97+
subject.sort_generate_blocks.each_with_index do |generate_block, i|
98+
expect(generate_block[:metadata]).to eq(metadatas[i])
99+
end
100+
end
101+
end
55102
end
56103

57104
describe '#generate' do

0 commit comments

Comments
 (0)