feat: appointment type inference, procedure codes on cards, claim attachment fixes
- Add appointment type categories matching insurance claim form (recall, filling, pedo, dentures, implant, endo, crown, perio, extraction, ortho, consultation, emergency, other) - Auto-infer appointment type from CDT codes with priority rules (endo > implant > crown > ...) - typeLocked flag prevents auto-overwrite when user manually sets type - Show appointment type label and procedure codes on schedule cards - Background sync on /day route retroactively fixes stale appointment types - Fix PUT /api/claims/:id to save claimFiles (previously silently dropped) - Auto-link AppointmentFile records to ClaimFile when claim is created or updated - Fix D5750 (denture reline) CDT range to map correctly to dentures category - Fix typeLocked Zod rejection in appointment update route Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -647,17 +647,34 @@ class AutomationUnitedDHClaimSubmit:
|
||||
))
|
||||
)
|
||||
|
||||
# Explicit wait: hold until Angular has auto-filled the location dropdown
|
||||
# Select Treatment Location (first dropdown) — page auto-fills Billing Entity and rest
|
||||
print("[UnitedDH Claim] step3: Selecting Treatment Location...")
|
||||
location_selected = False
|
||||
try:
|
||||
WebDriverWait(self.driver, 10).until(
|
||||
lambda d: d.find_elements(By.XPATH,
|
||||
"//ng-select//span[contains(@class,'ng-value-label') and normalize-space(text())!=''] | "
|
||||
"//ng-select//div[contains(@class,'ng-value') and normalize-space(.)!='']"
|
||||
)
|
||||
location_ng = self.driver.find_element(By.XPATH,
|
||||
"//label[contains(text(),'Treatment Location') or contains(text(),'treatment location')]"
|
||||
"/..//ng-select | "
|
||||
"(//ng-select)[1]"
|
||||
)
|
||||
print("[UnitedDH Claim] step3: Location auto-filled")
|
||||
except TimeoutException:
|
||||
print("[UnitedDH Claim] step3: Location field did not populate in time — proceeding anyway")
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", location_ng)
|
||||
time.sleep(0.3)
|
||||
location_ng.click()
|
||||
time.sleep(1)
|
||||
first_option = WebDriverWait(self.driver, 5).until(
|
||||
EC.element_to_be_clickable((By.XPATH,
|
||||
"//ng-dropdown-panel//div[contains(@class,'ng-option') and not(contains(@class,'disabled'))]"
|
||||
))
|
||||
)
|
||||
option_text = first_option.text.strip()
|
||||
first_option.click()
|
||||
print(f"[UnitedDH Claim] step3: Selected Treatment Location: {option_text}")
|
||||
location_selected = True
|
||||
time.sleep(1) # wait for page to auto-fill remaining fields
|
||||
except Exception as e:
|
||||
print(f"[UnitedDH Claim] step3: Treatment Location selection failed: {e}")
|
||||
|
||||
if not location_selected:
|
||||
print("[UnitedDH Claim] step3: WARNING: Could not select Treatment Location — continuing anyway")
|
||||
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", continue_btn)
|
||||
continue_btn.click()
|
||||
@@ -706,28 +723,29 @@ class AutomationUnitedDHClaimSubmit:
|
||||
line.get("billedAmount") or
|
||||
line.get("fee") or ""
|
||||
).strip()
|
||||
print(f"[UnitedDH Claim] step4: line {idx}: code={code}, billed={billed}")
|
||||
tooth = str(line.get("toothNumber") or line.get("tooth_number") or "").strip()
|
||||
surface = str(line.get("toothSurface") or line.get("tooth_surface") or "").strip().upper()
|
||||
print(f"[UnitedDH Claim] step4: line {idx}: code={code}, billed={billed}, tooth={tooth}, surface={surface}")
|
||||
|
||||
# For lines after the first, click btnAddItem to open a new procedure row
|
||||
if idx > 0:
|
||||
try:
|
||||
add_btn = WebDriverWait(self.driver, 8).until(
|
||||
EC.element_to_be_clickable((By.ID, "btnAddItem"))
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", add_btn)
|
||||
add_btn.click()
|
||||
print(f"[UnitedDH Claim] step4: clicked btnAddItem to start row {idx}")
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
print(f"[UnitedDH Claim] step4: could not click btnAddItem for row {idx}: {e}")
|
||||
# For ALL rows, click btnAddItem to open/activate the procedure row
|
||||
try:
|
||||
add_btn = WebDriverWait(self.driver, 10).until(
|
||||
EC.element_to_be_clickable((By.ID, "btnAddItem"))
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", add_btn)
|
||||
add_btn.click()
|
||||
print(f"[UnitedDH Claim] step4: clicked btnAddItem to open row {idx}")
|
||||
time.sleep(1)
|
||||
except Exception as e:
|
||||
print(f"[UnitedDH Claim] step4: could not click btnAddItem to open row {idx}: {e}")
|
||||
|
||||
# Type CDT code in procedureCode input
|
||||
try:
|
||||
proc_input = WebDriverWait(self.driver, 8).until(
|
||||
proc_input = WebDriverWait(self.driver, 10).until(
|
||||
EC.element_to_be_clickable((By.ID, "procedureCode"))
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", proc_input)
|
||||
proc_input.click()
|
||||
self.driver.execute_script("arguments[0].click();", proc_input)
|
||||
proc_input.send_keys(Keys.CONTROL + "a")
|
||||
proc_input.send_keys(Keys.DELETE)
|
||||
proc_input.send_keys(code)
|
||||
@@ -750,6 +768,50 @@ class AutomationUnitedDHClaimSubmit:
|
||||
print(f"[UnitedDH Claim] step4: could not click btnAddItem for billed amount row {idx}: {e}")
|
||||
continue
|
||||
|
||||
# Fill tooth number
|
||||
if tooth:
|
||||
try:
|
||||
tooth_input = WebDriverWait(self.driver, 5).until(
|
||||
EC.element_to_be_clickable((By.ID, "tooth"))
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", tooth_input)
|
||||
tooth_input.click()
|
||||
tooth_input.send_keys(Keys.CONTROL + "a")
|
||||
tooth_input.send_keys(Keys.DELETE)
|
||||
tooth_input.send_keys(tooth)
|
||||
print(f"[UnitedDH Claim] step4: entered tooth number: {tooth} for row {idx}")
|
||||
time.sleep(0.3)
|
||||
except Exception as e:
|
||||
print(f"[UnitedDH Claim] step4: could not fill tooth number for row {idx}: {e}")
|
||||
|
||||
# Click surface boxes (B, D, F, L, M, O, etc.) — only present for filling codes
|
||||
if surface:
|
||||
try:
|
||||
# Check surface box group is present before trying to click
|
||||
surface_boxes = self.driver.find_elements(By.XPATH,
|
||||
"//div[contains(@class,'claim-add-item-group__box')]"
|
||||
)
|
||||
if surface_boxes:
|
||||
for letter in surface:
|
||||
if not letter.strip():
|
||||
continue
|
||||
try:
|
||||
box = self.driver.find_element(By.XPATH,
|
||||
f"//div[contains(@class,'claim-add-item-group__box') "
|
||||
f"and not(contains(@class,'--disabled')) "
|
||||
f"and @id='{letter}']"
|
||||
)
|
||||
self.driver.execute_script("arguments[0].scrollIntoView({block:'center'});", box)
|
||||
box.click()
|
||||
print(f"[UnitedDH Claim] step4: clicked surface '{letter}' for row {idx}")
|
||||
time.sleep(0.2)
|
||||
except Exception:
|
||||
print(f"[UnitedDH Claim] step4: surface '{letter}' not found or disabled for row {idx}")
|
||||
else:
|
||||
print(f"[UnitedDH Claim] step4: no surface boxes on page for row {idx} — skipping")
|
||||
except Exception as e:
|
||||
print(f"[UnitedDH Claim] step4: surface click error for row {idx}: {e}")
|
||||
|
||||
# Fill billed amount
|
||||
if billed:
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user