diff --git a/scripts/hyde/elmhurst_lib.py b/scripts/hyde/elmhurst_lib.py index fb99966fb..72f2fb9bc 100644 --- a/scripts/hyde/elmhurst_lib.py +++ b/scripts/hyde/elmhurst_lib.py @@ -467,6 +467,63 @@ def select_boiler(page: Page, query: str, ref: str) -> str: return "ok" +def clear_main_heating_code(page: Page) -> None: + """Empty Main Heating 1's SAP code via a real server postback (set the + cascade's top-level dropdown to '' + OK). REQUIRED before `set_pcdb_boiler`: + while any code is set, the PCDF reference textbox and the boiler-search + magnifying glass both render `aspNetDisabled`. They only enable when the + code is empty server-side (a JS-clear alone flips the class cosmetically but + leaves the postback unwired).""" + page.evaluate( + "(id)=>{const e=document.getElementById(id); if(e)e.click();}", + f"{MH1}ButtonMainHeatingCode", + ) + page.wait_for_timeout(SETTLE_MS * 3) + page.evaluate( + """(id)=>{const s=document.getElementById(id);if(s){s.value=''; + s.dispatchEvent(new Event('change',{bubbles:true}));}}""", + f"{HEATING_DIALOG}DropDownList1", + ) + page.wait_for_timeout(SETTLE_MS * 3) + dialog_commit(page, "OK") + page.wait_for_timeout(SETTLE_MS * 2) + + +def set_pcdb_boiler(page: Page, pcdb_index: "int | str") -> str: + """Set Main Heating 1 to the EXACT PCDB boiler by its EPC + `main_heating_index_number` (e.g. 18908 = Worcester Greenstar 4000, + GR4700iW 25 C NG, 88.70%). Elmhurst resolves it to the product's PCDB + winter efficiency — the same value the SAP engine uses — so the worksheet + and our calculator compare like-for-like (not against the generic BGW + SAP-Table 84%). Returns the resolved boiler description. + + Hard-won mechanism (supersedes the old "PCDB disabled" note): + 1. The PCDF reference textbox is only writable while the main heating CODE + is empty — call `clear_main_heating_code(page)` first. + 2. The index must be entered via REAL keyboard + Tab. A JS-set `.value` + does NOT survive the field's AutoPostBack, so the boiler never + resolves (the original failure mode). Ctrl-A + type + Tab works. + 3. The `TextBoxPCDFBoilerReference` direct-entry path is far simpler than + the magnifying-glass grid (whose modal has no layout box, so + mouse/Playwright clicks can't target rows). The grid search DOES work + (JS-focus the FullSearch box + `keyboard.type` + fire + HyperLinkActionBoilerSearch → "Ref No" column == the PCDB index) if a + name lookup is ever needed, but direct entry is preferred.""" + fld = f"{MH1}TextBoxPCDFBoilerReference" + page.evaluate( + "(id)=>{const e=document.getElementById(id);if(e){e.focus();e.select();}}", fld + ) + page.wait_for_timeout(SETTLE_MS) + page.keyboard.press("Control+a") + page.keyboard.type(str(pcdb_index), delay=40) + page.keyboard.press("Tab") + page.wait_for_timeout(SETTLE_MS * 5) # AutoPostBack resolves the PCDB record + return page.evaluate( + """()=>{const e=document.querySelector('[id*=LabelMHSSapCodeDescription]'); + return e?e.innerText.trim():'';}""" + ) + + def read_default_uvalue( page: Page, suffix: Optional[str] = None, label_regex: str = r"Default U-value" ) -> Optional[float]: