Skip to content

Commit 0fe70fd

Browse files
authored
Merge pull request #10 from nealwp/error-dialog
Error dialog
2 parents 6d1bf22 + 5b3e074 commit 0fe70fd

10 files changed

+243
-47
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -13,4 +13,5 @@ lib/*
1313
*.json
1414
files
1515
*.drawio*
16+
*.docx
1617
.venv

pytest.ini

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
[pytest]
2+
pythonpath = .

src/exporter/bell_summary.py

+14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ def generate_bell_format_summary(data):
1818
doc.add_paragraph(f'TYPE OF CLAIM:\t\t{data["claimant"].claim}')
1919
doc.add_paragraph(f'DATE OF APPLICATION:\t{datetime.strftime(data["claimant"].pdof, "%m/%d/%Y")}')
2020
doc.add_paragraph(f'ALLEGED ONSET DATE:\t{data["onset_date"]}')
21+
doc.add_paragraph(f'DATE LATE INSURED:\t\t{data["claimant"].last_insured_date}')
2122
doc.add_paragraph(f'DOB:\t\t\t\t{data["birthdate"]}')
2223
doc.add_paragraph(f'AGE:\t\t\t\t{data["age"]}')
2324
doc.add_paragraph(f'EDUCATION:\t\t\t{data["education"]}')
@@ -66,6 +67,19 @@ def generate_bell_format_summary(data):
6667
p = doc.add_paragraph()
6768
p.add_run(f'{comment.date}: {comment.text} ({exhibit}/{comment.exhibit_page})')
6869

70+
doc.add_paragraph('')
71+
doc.add_paragraph('')
72+
73+
doc.add_paragraph('CONSULTATIVE EXAM:')
74+
75+
doc.add_paragraph('')
76+
doc.add_paragraph('')
77+
78+
doc.add_paragraph('MEDICAL-VOCATIONAL GRIDRULE AND/OR RULING:')
79+
80+
doc.add_paragraph('')
81+
doc.add_paragraph('')
82+
6983
for section in doc.sections:
7084
section.left_margin = Inches(1)
7185
section.right_margin = Inches(1)

src/pdf/__init__.py

+4
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@ def age(self) -> int:
2727
return None
2828

2929
def age_at_onset(self) -> int:
30+
31+
if self.onset_date == "N/A":
32+
return None
33+
3034
if self.birthdate and self.onset_date:
3135
birthdate = datetime.strptime(self.birthdate, '%m/%d/%Y')
3236
onset_date = datetime.strptime(self.onset_date, '%m/%d/%Y')

src/pdf/scanner.py

+60-34
Original file line numberDiff line numberDiff line change
@@ -129,14 +129,32 @@ def scan_pdf_for_summary(pdf_path):
129129

130130

131131
def parse_client_info(page_text):
132-
133-
lines = page_text.splitlines()
134-
lines = [line for line in lines if line]
135-
client_data = lines[:7]
136132
client_info = {}
137-
for e in client_data:
138-
e = e.split(':')
139-
client_info[e[0]] = e[1].lstrip()
133+
lines = page_text.splitlines()
134+
135+
for line in lines:
136+
if line.startswith("Alleged Onset:"):
137+
client_info["Alleged Onset"] = line.split(":")[1].strip()
138+
continue
139+
if line.startswith("Application:"):
140+
client_info["Application"] = line.split(":")[1].strip()
141+
continue
142+
if line.startswith("Claim Type:"):
143+
client_info["Claim Type"] = line.split(":")[1].strip()
144+
continue
145+
if line.startswith("Claimant:"):
146+
client_info["Claimant"] = line.split(":")[1].strip()
147+
continue
148+
if line.startswith("Last Change:"):
149+
client_info["Last Change"] = line.split(":")[1].strip()
150+
continue
151+
if line.startswith("Last Insured:"):
152+
client_info["Last Insured"] = line.split(":")[1].strip()
153+
continue
154+
if line.startswith("SSN:"):
155+
client_info["SSN"] = line.split(":")[1].strip()
156+
continue
157+
140158
return client_info
141159

142160

@@ -152,41 +170,49 @@ def parse_work_history(page_text):
152170
'job_title': e.split(": ")[1],
153171
'intensity': '',
154172
'skill_level': '',
155-
}
173+
}
156174
return work_history
157175

158176

159177
def get_exhibits_from_pdf(doc):
160-
try:
161-
outlines = doc.get_outlines()
162-
sys.setrecursionlimit(999999999)
163-
index = 1
164-
provider = ''
165-
exhibits = {}
166-
for (level, title, dest, a, se) in outlines:
167-
if level == 2:
168-
provider = title
169-
id = provider.split(":")[0]
170-
provider_name = provider.split(":")[1].replace("Doc. Dt.", "").replace("Tmt. Dt.", "").strip()
171-
provider_dates = re.sub(r"\(\d* page.*", "", provider.split(":")[2]).strip()
172-
from_date = provider_dates.split("-")[0]
173-
try:
174-
to_date = provider_dates.split("-")[1]
175-
except IndexError:
176-
to_date = from_date
177-
ex = Exhibit(provider_name=provider_name, from_date=from_date, to_date=to_date, comments=[])
178-
exhibits[id] = ex
179-
if level == 3:
180-
index += 1
181-
except PDFNoOutlines:
182-
exhibits = {}
183-
sys.setrecursionlimit(1000)
184-
print('PDF has no outlines to reference.')
185-
178+
exhibits = {}
179+
outlines = doc.get_outlines()
180+
sys.setrecursionlimit(999999999)
181+
index = 1
182+
for (level, title, dest, a, se) in outlines:
183+
if level == 2:
184+
id, provider_name, from_date, to_date = parse_title(title)
185+
ex = Exhibit(provider_name=provider_name, from_date=from_date, to_date=to_date, comments=[])
186+
exhibits[id] = ex
187+
if level == 3:
188+
index += 1
186189
sys.setrecursionlimit(1000)
187190
return exhibits
188191

189192

193+
def parse_title(title):
194+
split_title = title.split(":")
195+
id = split_title[0]
196+
provider_name = split_title[1].replace("Doc. Dt.", "").replace("Tmt. Dt.", "").strip()
197+
198+
# if no dates, return empty
199+
if len(split_title) == 2:
200+
provider_name = re.sub(r"\(\d* page.*", "", provider_name).strip()
201+
return (id, provider_name, "", "")
202+
203+
provider_dates = re.sub(r"\(\d* page.*", "", split_title[2]).strip().split("-")
204+
205+
# if one date, return both as date
206+
if len(provider_dates) == 1:
207+
date = provider_dates[0]
208+
return (id, provider_name, date, date)
209+
210+
from_date = provider_dates[0]
211+
to_date = provider_dates[1]
212+
213+
return (id, provider_name, from_date, to_date)
214+
215+
190216
def parse_page_comments(annots):
191217

192218
page_comments = []

src/ui/errordialog.py

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
from tkinter import Toplevel, Label, LEFT, Button
2+
3+
4+
class ErrorDialog(Toplevel):
5+
def __init__(self, parent, error):
6+
super().__init__(parent)
7+
self.title("Error")
8+
Label(self, text=error, anchor='w', justify=LEFT).pack(pady=5, padx=5)
9+
10+
Button(self, text='Close', command=self.destroy).pack(pady=10)
11+
12+
self.transient(parent)
13+
self.grab_set()
14+
self.geometry("+%d+%d" % (parent.winfo_rootx()+50, parent.winfo_rooty()+50))

src/ui/summaryform.py

+12-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
from datetime import datetime
2-
from tkinter import Toplevel, Button, Label, Entry, StringVar, Text, LabelFrame, Radiobutton
2+
from tkinter import Toplevel, Button, Label, Entry, StringVar, Text, LabelFrame, Radiobutton, LEFT
33
from tkinter.ttk import Combobox
4-
4+
from traceback import format_exc
55
from src.helpers import get_save_path, get_file_path, get_age, get_age_at_onset
66
from src.pdf.scanner import scan_for_comments, scan_pdf_for_summary
77
from src.ui.workhistoryform import WorkHistoryForm
8+
from src.ui.errordialog import ErrorDialog
89
from src.exporter import generate_summary
910

1011

@@ -179,9 +180,15 @@ def _get_summary_data(self):
179180
modal.grab_set()
180181
modal.geometry("+%d+%d" % (self.winfo_rootx()+50, self.winfo_rooty()+50))
181182
self.update()
182-
self.medical_record = scan_pdf_for_summary(self.pdf_path)
183-
self._fill_entry_fields()
184-
modal.destroy()
183+
try:
184+
self.medical_record = scan_pdf_for_summary(self.pdf_path)
185+
self._fill_entry_fields()
186+
modal.destroy()
187+
except Exception:
188+
modal.destroy()
189+
error = format_exc()
190+
error_modal = ErrorDialog(self, error)
191+
self.update()
185192

186193
def _fill_entry_fields(self):
187194
mr = self.medical_record

tests/helpers/example_page_1.txt

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
Claimant: John Person Doe
2+
SSN: 000-00-0000
3+
Last Change: 01/01/1970
4+
Alleged Onset: N/A
5+
6+
Claim Type: T16
7+
Application: 01/01/2023
8+
Last Insured: N/A
9+
10+
A. Payment Documents/Decisions
11+
Title
12+
1A: Disability Determination Explanation - DDE
13+
2A: Disability Determination Transmittal - 831
14+
3A: T16 Cease/Continue Disability Determination and Transmittal - 832
15+
4A: Disability Determination Explanation - DDE
16+
5A: Disability Determination Explanation - DDE
17+
6A: T16 Cease/Continue Disability Determination and Transmittal - 832
18+
7A: Disability Determination Explanation - DDE
19+
20+
Decision Date
21+
08/06/2018
22+
08/06/2018
23+
08/30/2022
24+
08/30/2022
25+
02/23/2023
26+
05/17/2023
27+
05/17/2023

tests/helpers/example_page_1_alt.txt

+41
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
Claimant: Jane Person Doe
2+
SSN: 000-00-0000
3+
Last Change: 01/01/1970
4+
Alleged Onset: 01/01/2009
5+
6+
A. Payment Documents/Decisions
7+
Title
8+
1A: Disability Determination Transmittal - 831
9+
2A: Disability Determination Explanation - DDE
10+
3A: Disability Determination Transmittal - 831
11+
4A: Disability Determination Explanation - DDE
12+
13+
Claim Type: T16
14+
Application: 02/26/2022
15+
Last Insured: N/A
16+
17+
B. Jurisdictional Documents/Notices
18+
Title
19+
1B: T16 Notice of Disapproved Claim - L444
20+
2B: Request for Reconsideration - 561
21+
3B: T16 Disability Reconsideration Notice - L1130
22+
4B: SSA-1696 - Claimant’s Appointment of a Representative - 1696
23+
5B: Fee Agreement for Representation before SSA - FEEAGRMT
24+
6B: SSA-1696 - Claimant’s Appointment of a Representative - 1696
25+
7B: Fee Agreement for Representation before SSA - FEEAGRMT
26+
8B: Request for Hearing by ALJ - 501
27+
9B: Hearing Agreement Form - HRNGAGREEFRM
28+
10B: Outgoing ODAR Correspondence - OUTODARC
29+
11B: Outgoing ODAR Correspondence - OUTODARC
30+
12B: Request for Hearing Acknowledgement Letter - HRGACK
31+
13B: Hearing Agreement Form - HRNGAGREEFRM
32+
14B: Hearing Notice - 507
33+
15B: Acknowledge Notice of Hearing - 504
34+
35+
D. Non-Disability Development
36+
Title
37+
1D: Application for Supplemental Security Income Benefits - 8000
38+
2D: Detailed Earnings Query - DEQY
39+
3D: Summary Earnings Query - SEQY
40+
4D: Certified Earnings Records - CERTERN
41+
5D: New Hire, Quarter Wage, Unemployment Query (NDNH) - NDNH

tests/test_pdfscanner.py

+68-8
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,71 @@
1-
from modules.pdfscanner import *
1+
from src.pdf.scanner import parse_title, parse_client_info
22

3-
file_path = r'.\\files\\2909274-cecilia_phillips-case_file_exhibited_bookmarked-8-10-2022- w notes.pdf'
43

5-
def test_read_medical_record():
6-
medical_record = MedicalRecord(file_path)
7-
assert(medical_record)
4+
def test_parse_title():
5+
test_cases = [
6+
{
7+
"test": "6F: 6F - 1 of 13 Office Treatment Records - OFFCREC LIFESTREAM BEHAIVORAL CENTER Tmt. Dt.: 12/28/2016-08/30/2021 (23 pages)",
8+
"expected": (
9+
"6F",
10+
"6F - 1 of 13 Office Treatment Records - OFFCREC LIFESTREAM BEHAIVORAL CENTER",
11+
"12/28/2016",
12+
"08/30/2021",
13+
)
14+
},
15+
{
16+
"test": "16F: 16F - 1 of 112 Emergency Department Records - EMERREC UF HEALTH GAINESVILLE Tmt. Dt.: 01/09/2023 (17 pages)",
17+
"expected": (
18+
"16F",
19+
"16F - 1 of 112 Emergency Department Records - EMERREC UF HEALTH GAINESVILLE",
20+
"01/09/2023",
21+
"01/09/2023",
22+
)
23+
},
24+
{
25+
"test": "19F: 19F - 1 of 23 Medical Evidence of Record - MER VOCATIONAL REHABILITATION (12 pages)",
26+
"expected": (
27+
"19F",
28+
"19F - 1 of 23 Medical Evidence of Record - MER VOCATIONAL REHABILITATION",
29+
"",
30+
"",
31+
)
32+
},
33+
]
834

9-
def test_get_exhibits_from_medical_record():
10-
medical_record = MedicalRecord(file_path)
11-
exhibits = medical_record.exhibits
35+
for case in test_cases:
36+
result = parse_title(case["test"])
37+
assert result == case["expected"]
38+
39+
40+
def test_parse_client_info():
41+
expected = [
42+
{
43+
"Alleged Onset": "N/A",
44+
"Application": "01/01/2023",
45+
"Claim Type": "T16",
46+
"Claimant": "John Person Doe",
47+
"Last Change": "01/01/1970",
48+
"Last Insured": "N/A",
49+
"SSN": "000-00-0000",
50+
},
51+
{
52+
"Alleged Onset": "01/01/2009",
53+
"Application": "02/26/2022",
54+
"Claim Type": "T16",
55+
"Claimant": "Jane Person Doe",
56+
"Last Change": "01/01/1970",
57+
"Last Insured": "N/A",
58+
"SSN": "000-00-0000",
59+
}
60+
]
61+
62+
inputs = [
63+
"tests/helpers/example_page_1.txt",
64+
"tests/helpers/example_page_1_alt.txt"
65+
]
66+
67+
for i, file in enumerate(inputs):
68+
fd = open(file, "r")
69+
page_one = str(fd.read())
70+
result = parse_client_info(page_one)
71+
assert result == expected[i]

0 commit comments

Comments
 (0)