Skip to content

Commit 0ae36e3

Browse files
costacalvinCalvin Costa
andauthored
stamp signature added for Form 21-0779 (#25582)
* stamp signature added for Form 21-0779 * removing unnecessary mapping * update PDF deletion through controller * rspec updates * update rspec * feedback updates --------- Co-authored-by: Calvin Costa <[email protected]>
1 parent 6962e42 commit 0ae36e3

File tree

7 files changed

+185
-6
lines changed

7 files changed

+185
-6
lines changed

app/models/saved_claim/form210779.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ def send_confirmation_email
3131
# )
3232
end
3333

34+
# Override to_pdf to add nursing home official signature stamp
35+
def to_pdf(file_name = nil, fill_options = {})
36+
pdf_path = PdfFill::Filler.fill_form(self, file_name, fill_options)
37+
PdfFill::Forms::Va210779.stamp_signature(pdf_path, parsed_form)
38+
end
39+
3440
def veteran_name
3541
first = parsed_form.dig('veteranInformation', 'fullName', 'first')
3642
last = parsed_form.dig('veteranInformation', 'fullName', 'last')

lib/pdf_fill/forms/field_mappings/va210779.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ class Va210779
292292
type: 'Text'
293293
}
294294
},
295-
# signature: 'TODO',
295+
# NOTE: 'signature' field is not mapped here - it's stamped onto the PDF via stamp_signature method
296296
signatureDate: {
297297
month: {
298298
key: 'F[0].Page_1[0].Date_Signed_Month[0]',

lib/pdf_fill/forms/va210779.rb

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,13 @@ class Va210779 < FormBase
1515
'intermediate' => 2
1616
}.freeze
1717

18+
# Coordinates for the 21-0779 signature field
19+
# Question 20: SIGNATURE OF NURSING HOME OFFICIAL (bottom left of page 1)
20+
SIGNATURE_X = 60
21+
SIGNATURE_Y = 70
22+
SIGNATURE_PAGE = 0 # zero-indexed; 0 == page 1
23+
SIGNATURE_SIZE = 10
24+
1825
def merge_fields(_options = {})
1926
reformat_vet_info
2027
reformat_claimant_info
@@ -23,6 +30,32 @@ def merge_fields(_options = {})
2330
@form_data
2431
end
2532

33+
# Stamp a typed signature string onto the PDF using DatestampPdf
34+
#
35+
# @param pdf_path [String] Path to the PDF to stamp
36+
# @param form_data [Hash] The form data containing the signature
37+
# @return [String] Path to the stamped PDF (or the original path if signature is blank/on failure)
38+
def self.stamp_signature(pdf_path, form_data)
39+
signature_text = form_data.dig('generalInformation', 'signature')
40+
41+
return pdf_path if signature_text.nil? || signature_text.to_s.strip.empty?
42+
43+
PDFUtilities::DatestampPdf.new(pdf_path).run(
44+
text: signature_text,
45+
x: SIGNATURE_X,
46+
y: SIGNATURE_Y,
47+
page_number: SIGNATURE_PAGE,
48+
size: SIGNATURE_SIZE,
49+
text_only: true,
50+
timestamp: '',
51+
template: pdf_path,
52+
multistamp: true
53+
)
54+
rescue => e
55+
Rails.logger.error('Form210779: Error stamping signature', error: e.message, backtrace: e.backtrace)
56+
pdf_path # Return original PDF if stamping fails
57+
end
58+
2659
def reformat_vet_info
2760
vet_info = @form_data['veteranInformation']
2861
return unless vet_info

spec/controllers/v0/form210779_controller_spec.rb

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,8 @@ def confirmation_number
115115

116116
describe 'get #download_pdf' do
117117
let(:claim) { create(:va210779) }
118-
let(:temp_file_path) { "tmp/pdfs/21-0779_#{claim.id}.pdf" }
118+
let(:filled_pdf_path) { "tmp/pdfs/21-0779_#{claim.id}.pdf" }
119+
let(:stamped_pdf_path) { 'tmp/8607c198992feedf899d78f98e5af856.pdf' }
119120

120121
before do
121122
allow(Flipper).to receive(:enabled?).with(:form_0779_enabled, nil).and_return(true)
@@ -137,7 +138,11 @@ def confirmation_number
137138
end
138139

139140
it 'deletes temporary PDF file after sending' do
140-
expect(File).to receive(:delete).with(temp_file_path)
141+
allow_any_instance_of(SavedClaim::Form210779).to receive(:to_pdf).and_return(stamped_pdf_path)
142+
allow(File).to receive(:exist?).and_call_original
143+
allow(File).to receive(:exist?).with(stamped_pdf_path).and_return(true)
144+
allow(File).to receive(:read).with(stamped_pdf_path).and_return('PDF content')
145+
expect(File).to receive(:delete).with(stamped_pdf_path).at_least(:once)
141146
get(:download_pdf, params: { guid: claim.guid })
142147
end
143148

@@ -153,8 +158,11 @@ def confirmation_number
153158
end
154159

155160
it 'deletes temporary file even when file read fails' do
156-
allow(File).to receive(:read).with(temp_file_path).and_raise(StandardError, 'Read error')
157-
expect(File).to receive(:delete).with(temp_file_path)
161+
allow_any_instance_of(SavedClaim::Form210779).to receive(:to_pdf).and_return(stamped_pdf_path)
162+
allow(File).to receive(:exist?).and_call_original
163+
allow(File).to receive(:exist?).with(stamped_pdf_path).and_return(true)
164+
allow(File).to receive(:read).with(stamped_pdf_path).and_raise(StandardError, 'Read error')
165+
expect(File).to receive(:delete).with(stamped_pdf_path).at_least(:once)
158166

159167
get(:download_pdf, params: { guid: claim.guid })
160168
expect(response).to have_http_status(:internal_server_error)

spec/lib/pdf_fill/forms/va210779_spec.rb

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,93 @@
1111
test_data_types: %w[simple],
1212
run_at: '2025-10-24T18:48:27Z'
1313
}
14+
15+
describe '.stamp_signature' do
16+
let(:pdf_path) { 'tmp/test_form.pdf' }
17+
let(:signature_text) { 'John Doe' }
18+
let(:form_data) do
19+
{
20+
'generalInformation' => {
21+
'signature' => signature_text,
22+
'nursingOfficialName' => 'Jane Smith'
23+
}
24+
}
25+
end
26+
27+
before do
28+
allow(PDFUtilities::DatestampPdf).to receive(:new).and_return(
29+
double(run: 'tmp/stamped.pdf')
30+
)
31+
end
32+
33+
context 'with signature in generalInformation.signature' do
34+
it 'stamps the signature on the PDF' do
35+
expect(PDFUtilities::DatestampPdf).to receive(:new).with(pdf_path).and_return(
36+
double(run: 'tmp/stamped.pdf')
37+
)
38+
39+
result = described_class.stamp_signature(pdf_path, form_data)
40+
expect(result).to eq('tmp/stamped.pdf')
41+
end
42+
43+
it 'calls DatestampPdf with correct parameters' do
44+
datestamp_double = instance_double(PDFUtilities::DatestampPdf)
45+
allow(PDFUtilities::DatestampPdf).to receive(:new).with(pdf_path).and_return(datestamp_double)
46+
47+
expect(datestamp_double).to receive(:run).with(
48+
text: signature_text,
49+
x: described_class::SIGNATURE_X,
50+
y: described_class::SIGNATURE_Y,
51+
page_number: described_class::SIGNATURE_PAGE,
52+
size: described_class::SIGNATURE_SIZE,
53+
text_only: true,
54+
timestamp: '',
55+
template: pdf_path,
56+
multistamp: true
57+
).and_return('tmp/stamped.pdf')
58+
59+
described_class.stamp_signature(pdf_path, form_data)
60+
end
61+
end
62+
63+
context 'with no signature data' do
64+
let(:form_data) { { 'generalInformation' => {} } }
65+
66+
it 'returns the original PDF path without stamping' do
67+
expect(PDFUtilities::DatestampPdf).not_to receive(:new)
68+
result = described_class.stamp_signature(pdf_path, form_data)
69+
expect(result).to eq(pdf_path)
70+
end
71+
end
72+
73+
context 'with blank signature' do
74+
let(:form_data) do
75+
{ 'generalInformation' => { 'signature' => ' ' } }
76+
end
77+
78+
it 'returns the original PDF path without stamping' do
79+
expect(PDFUtilities::DatestampPdf).not_to receive(:new)
80+
result = described_class.stamp_signature(pdf_path, form_data)
81+
expect(result).to eq(pdf_path)
82+
end
83+
end
84+
85+
context 'when stamping raises an error' do
86+
let(:error_message) { 'PDF stamping failed' }
87+
88+
before do
89+
allow(PDFUtilities::DatestampPdf).to receive(:new).and_raise(StandardError, error_message)
90+
end
91+
92+
it 'logs the error and returns the original PDF path' do
93+
expect(Rails.logger).to receive(:error).with(
94+
'Form210779: Error stamping signature',
95+
hash_including(error: error_message)
96+
)
97+
98+
result = described_class.stamp_signature(pdf_path, form_data)
99+
expect(result).to eq(pdf_path)
100+
end
101+
end
102+
end
14103
end

spec/models/saved_claim/form210779_spec.rb

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,4 +55,47 @@
5555
claim.process_attachments!
5656
end
5757
end
58+
59+
describe '#to_pdf' do
60+
let(:saved_claim) { create(:va210779) }
61+
let(:pdf_path) { 'tmp/pdfs/21-0779_test.pdf' }
62+
let(:stamped_pdf_path) { 'tmp/pdfs/21-0779_test_stamped.pdf' }
63+
64+
before do
65+
allow(PdfFill::Filler).to receive(:fill_form).and_return(pdf_path)
66+
allow(PdfFill::Forms::Va210779).to receive(:stamp_signature).and_return(stamped_pdf_path)
67+
end
68+
69+
it 'generates the PDF using PdfFill::Filler' do
70+
expect(PdfFill::Filler).to receive(:fill_form).with(saved_claim, nil, {}).and_return(pdf_path)
71+
saved_claim.to_pdf
72+
end
73+
74+
it 'calls stamp_signature with the filled PDF and parsed form data' do
75+
expect(PdfFill::Forms::Va210779).to receive(:stamp_signature).with(
76+
pdf_path,
77+
saved_claim.parsed_form
78+
).and_return(stamped_pdf_path)
79+
80+
saved_claim.to_pdf
81+
end
82+
83+
it 'returns the stamped PDF path' do
84+
result = saved_claim.to_pdf
85+
expect(result).to eq(stamped_pdf_path)
86+
end
87+
88+
it 'passes through file_name and fill_options to PdfFill::Filler' do
89+
file_name = 'custom_name.pdf'
90+
fill_options = { flatten: true }
91+
92+
expect(PdfFill::Filler).to receive(:fill_form).with(
93+
saved_claim,
94+
file_name,
95+
fill_options
96+
).and_return(pdf_path)
97+
98+
saved_claim.to_pdf(file_name, fill_options)
99+
end
100+
end
58101
end

spec/requests/v0/form210779_spec.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
end
5353

5454
it 'returns 500 when to_pdf returns error' do
55-
allow_any_instance_of(SavedClaim).to receive(:to_pdf).and_raise(StandardError, 'PDF generation error')
55+
allow_any_instance_of(SavedClaim::Form210779).to receive(:to_pdf).and_raise(StandardError, 'PDF generation error')
5656

5757
metrics = capture_statsd_calls do
5858
get("/v0/form210779/download_pdf/#{saved_claim.guid}", headers: {

0 commit comments

Comments
 (0)