fix: CCA claim fills tooth surfaces into SURFACE1-5 inputs

- Use ServicesSURFACE{n} editor ids (matching header mapping names);
  keep ServicesSURF{n} as a one-try fallback
- Derive missing surface columns from TOOTH+n when headers lack names
- Treat a failed surface fill as an error so the claim is not submitted

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-12 00:22:39 -04:00
co-authored by Claude Opus 5.5
parent 2ca42bb15f
commit 8937a3390c
@@ -677,6 +677,16 @@ class AutomationCCAClaimSubmit:
col_map[f"SURF{n}"] = col_map[key]
col_map[f"S{n}"] = col_map[key]
# Surface headers can have blank mapping names. The 5 surface
# columns sit directly after TOOTH, so derive any missing ones.
if "TOOTH" in col_map:
for n in range(1, 6):
if f"SURF{n}" not in col_map:
col_map[f"SURF{n}"] = col_map["TOOTH"] + n
col_map[f"S{n}"] = col_map["TOOTH"] + n
print(f"[CCA Claim grid] SURF{n} header missing, "
f"using TOOTH+{n} = {col_map['TOOTH'] + n}")
if col_map:
return col_map
except Exception as e:
@@ -893,19 +903,29 @@ class AutomationCCAClaimSubmit:
tooth_ok = click_cell_and_fill_retry(col_map["TOOTH"], "ServicesTOOTH", tooth)
# Surfaces — skip if empty
surface_ok = True
if surface_chars:
surf_ids = ["ServicesSURF1","ServicesSURF2","ServicesSURF3",
"ServicesSURF4","ServicesSURF5"]
# Editor input ids follow "Services" + header mapping name
# (ServicesCODE, ServicesTOOTH, ...). Surface headers are
# SURFACE1..5, so the inputs are ServicesSURFACE1..5.
for si, char in enumerate(surface_chars[:5]):
click_cell_and_fill_retry(col_map[f"SURF{si+1}"], surf_ids[si], char)
n = si + 1
col = col_map[f"SURF{n}"]
ok = click_cell_and_fill_retry(col, f"ServicesSURFACE{n}", char)
if not ok:
# Legacy id seen in older grid versions — one quick try
ok = click_cell_and_fill_retry(col, f"ServicesSURF{n}", char, attempts=1)
if not ok:
surface_ok = False
# Billed Amount
# QTY and Service Date auto-fill after CODE is entered and this cell is clicked
billed_ok = click_cell_and_fill_retry(col_map["BILLED_AMOUNT"], "ServicesBILLED_AMOUNT", billed_str)
if not (code_ok and tooth_ok and billed_ok):
if not (code_ok and tooth_ok and surface_ok and billed_ok):
missing = [name for name, ok in
[("code", code_ok), ("tooth", tooth_ok), ("billed amount", billed_ok)]
[("code", code_ok), ("tooth", tooth_ok),
("surface", surface_ok), ("billed amount", billed_ok)]
if not ok]
return (f"ERROR: failed to fill {', '.join(missing)} for service line "
f"{idx+1} (code={code}) — claim NOT submitted")