feat: add Remaining/Third Party columns, toggle PDF viewer, retire CMSP as separate insurance type
- Add remainingBenefit and thirdPartyInsurance columns to Patient; extract both from the MassHealth accumulator/member-detail pages during the eligibility check and surface them in the eligibility table - Add an updated-date display and a toggle to suppress the post-check PDF viewer popup (default off) on the insurance eligibility page - Rename CMSP-prefixed PDF filenames and UI copy to MH, since CMSP and MH now share the same worker - Fold CMSP into MassHealth/MH across patient/claim insurance-type dropdowns and the chatbot's eligibility routing, since they're the same insurance - Remove auto-download of saved eligibility PDFs; downloading is now manual Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -234,7 +234,7 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
|
||||
print("No new tab for eligibility; printing current page directly")
|
||||
|
||||
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
|
||||
pdf_filename = f"cmsp_eligibility_{safe_member}.pdf"
|
||||
pdf_filename = f"mh_eligibility_{safe_member}.pdf"
|
||||
pdf_data = self.driver.execute_cdp_cmd("Page.printToPDF", {"printBackground": True})
|
||||
pdf_bytes = base64.b64decode(pdf_data["data"])
|
||||
pdf_path = os.path.join(self.download_dir, pdf_filename)
|
||||
@@ -279,14 +279,57 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
|
||||
|
||||
# ── step 3b — print member details page as PDF via CDP ───────────────────────
|
||||
|
||||
def extract_third_party_insurance(self):
|
||||
"""Reads the "Third Party Liability" table (Policy Number | Coverage Type |
|
||||
Effective Date | Termination Date | Insurer Name | Insurer Payment Order)
|
||||
and returns the Insurer Name(s), or None if the table has no rows
|
||||
(i.e. the member has no third-party/2nd insurance).
|
||||
"""
|
||||
try:
|
||||
tables = self.driver.find_elements(By.TAG_NAME, "table")
|
||||
for table in tables:
|
||||
rows = table.find_elements(By.TAG_NAME, "tr")
|
||||
if not rows:
|
||||
continue
|
||||
|
||||
header_cells = [
|
||||
c.text.strip().lower()
|
||||
for c in (rows[0].find_elements(By.TAG_NAME, "th") or rows[0].find_elements(By.TAG_NAME, "td"))
|
||||
]
|
||||
if "insurer name" not in header_cells:
|
||||
continue
|
||||
|
||||
insurer_idx = header_cells.index("insurer name")
|
||||
insurers = []
|
||||
for row in rows[1:]:
|
||||
cells = row.find_elements(By.TAG_NAME, "td")
|
||||
if len(cells) <= insurer_idx:
|
||||
continue
|
||||
name = cells[insurer_idx].text.strip()
|
||||
if name:
|
||||
insurers.append(name)
|
||||
|
||||
third_party = ", ".join(insurers) if insurers else None
|
||||
self.extracted_data["third_party_insurance"] = third_party
|
||||
print(f"[extract_third_party_insurance] {third_party!r}")
|
||||
return third_party
|
||||
|
||||
print("[extract_third_party_insurance] No 'Third Party Liability' table found")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"[extract_third_party_insurance] failed: {e}")
|
||||
return None
|
||||
|
||||
def step3b_member_details_pdf(self):
|
||||
wait = WebDriverWait(self.driver, 30)
|
||||
try:
|
||||
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
|
||||
time.sleep(2)
|
||||
|
||||
self.extract_third_party_insurance()
|
||||
|
||||
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
|
||||
pdf_filename = f"cmsp_member_details_{safe_member}.pdf"
|
||||
pdf_filename = f"mh_member_details_{safe_member}.pdf"
|
||||
pdf_data = self.driver.execute_cdp_cmd("Page.printToPDF", {"printBackground": True})
|
||||
pdf_bytes = base64.b64decode(pdf_data["data"])
|
||||
pdf_path = os.path.join(self.download_dir, pdf_filename)
|
||||
@@ -341,7 +384,7 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
|
||||
time.sleep(3)
|
||||
|
||||
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
|
||||
pdf_filename = f"cmsp_history_{safe_member}.pdf"
|
||||
pdf_filename = f"mh_history_{safe_member}.pdf"
|
||||
pdf_data = self.driver.execute_cdp_cmd("Page.printToPDF", {"printBackground": True})
|
||||
pdf_bytes = base64.b64decode(pdf_data["data"])
|
||||
pdf_path = os.path.join(self.download_dir, pdf_filename)
|
||||
@@ -353,7 +396,68 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
|
||||
print(f"[step5_service_history_pdf] failed: {e}")
|
||||
return None
|
||||
|
||||
# ── step 6 — Tab B: accumulator → wait for data → CDP print ─────────────────
|
||||
# ── step 6 — Tab B: accumulator → extract remaining → CDP print ─────────────
|
||||
|
||||
def extract_remaining_amount(self):
|
||||
"""Reads the accumulator benefits table and returns the Remaining amount.
|
||||
|
||||
Layout (see sample PDF "Accumulator Details"):
|
||||
Type | Level | Network | Benefit Period | Period | Limit | Applied | Remaining
|
||||
Prefers the Type="Maximum", Level="Individual" row; falls back to the
|
||||
first data row with a non-empty Remaining cell if that combination
|
||||
isn't found (payer may only return one row, or reorder columns).
|
||||
"""
|
||||
try:
|
||||
wait = WebDriverWait(self.driver, 15)
|
||||
wait.until(EC.presence_of_element_located((By.TAG_NAME, "table")))
|
||||
tables = self.driver.find_elements(By.TAG_NAME, "table")
|
||||
|
||||
for table in tables:
|
||||
rows = table.find_elements(By.TAG_NAME, "tr")
|
||||
if not rows:
|
||||
continue
|
||||
|
||||
header_cells = [
|
||||
c.text.strip().lower()
|
||||
for c in (rows[0].find_elements(By.TAG_NAME, "th") or rows[0].find_elements(By.TAG_NAME, "td"))
|
||||
]
|
||||
if "remaining" not in header_cells:
|
||||
continue
|
||||
|
||||
remaining_idx = header_cells.index("remaining")
|
||||
type_idx = header_cells.index("type") if "type" in header_cells else None
|
||||
level_idx = header_cells.index("level") if "level" in header_cells else None
|
||||
|
||||
fallback_value = None
|
||||
best_value = None
|
||||
for row in rows[1:]:
|
||||
cells = row.find_elements(By.TAG_NAME, "td")
|
||||
if len(cells) <= remaining_idx:
|
||||
continue
|
||||
cell_texts = [c.text.strip() for c in cells]
|
||||
value = cell_texts[remaining_idx]
|
||||
if not value:
|
||||
continue
|
||||
if fallback_value is None:
|
||||
fallback_value = value
|
||||
|
||||
type_ok = type_idx is None or "maximum" in cell_texts[type_idx].lower()
|
||||
level_ok = level_idx is None or "individual" in cell_texts[level_idx].lower()
|
||||
if type_ok and level_ok:
|
||||
best_value = value
|
||||
break
|
||||
|
||||
remaining_value = best_value or fallback_value
|
||||
if remaining_value:
|
||||
self.extracted_data["remaining_amount"] = remaining_value
|
||||
print(f"[extract_remaining_amount] Remaining: {remaining_value}")
|
||||
return remaining_value
|
||||
|
||||
print("[extract_remaining_amount] No accumulator table with a 'Remaining' column found")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"[extract_remaining_amount] failed: {e}")
|
||||
return None
|
||||
|
||||
def step6_accumulator_pdf(self):
|
||||
wait = WebDriverWait(self.driver, 30)
|
||||
@@ -379,8 +483,10 @@ class AutomationCMSPEligibilityHistoryRemainingCheck:
|
||||
wait.until(lambda d: d.execute_script("return document.readyState") == "complete")
|
||||
time.sleep(4)
|
||||
|
||||
self.extract_remaining_amount()
|
||||
|
||||
safe_member = "".join(c for c in str(self.memberId) if c.isalnum() or c in "-_.")
|
||||
pdf_filename = f"cmsp_accumulator_{safe_member}.pdf"
|
||||
pdf_filename = f"mh_accumulator_{safe_member}.pdf"
|
||||
pdf_data = self.driver.execute_cdp_cmd("Page.printToPDF", {"printBackground": True})
|
||||
pdf_bytes = base64.b64decode(pdf_data["data"])
|
||||
pdf_path = os.path.join(self.download_dir, pdf_filename)
|
||||
|
||||
Reference in New Issue
Block a user