Files
janssen/Covance/Trash/download_test_results_v1.0.md
2026-06-09 08:22:49 +02:00

239 lines
9.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# download_test_results_v1.0.py — dokumentace
**Verze:** 1.0 · **Datum:** 2026-05-29
**Umístění:** `U:\PythonProject\Janssen\Covance_UCO3001\download_test_results_v1.0.py`
---
## 1. Účel
Automatické stažení reportu **Standard Test Results** z portálu Labcorp Sponsor
Portal (`xsp.labcorp.com`) pro studii **77242113UCO3001** (interní study ID
**36940**). Skript projde **všech 12 center** studie, u každého vyexportuje grid
do CSV a uloží ho timestampovaný do adresáře `Source/`.
> Pozn.: Stahuje se záložka **Standard** (ne Microbiology). URL končí
> `/standard-test-results`.
---
## 2. Spuštění
```bat
U:\PythonProject\Janssen\.venv\Scripts\python.exe ^
U:\PythonProject\Janssen\Covance_UCO3001\download_test_results_v1.0.py
```
- Prohlížeč běží **viditelně** (`headless=False`), maximalizovaný.
- Používá **persistent profile** (`browser_profile/` vedle skriptu) — session
(přihlášení) přežívá mezi spuštěními.
---
## 3. Konfigurace (konstanty v hlavičce skriptu)
| Konstanta | Hodnota / význam |
|---|---|
| `EMAIL` | `vbuzalka@its.jnj.com` (login přes iMedidata/OKTA na xsp.covance.com) |
| `PASSWORD` | heslo k účtu (uložené přímo v kódu) |
| `LOGIN_URL` | `https://xsp.covance.com/` — po přihlášení redirect na xsp.labcorp.com |
| `OUT_DIR` | `U:\PythonProject\Janssen\Covance_UCO3001\Source` |
| `PROFILE_DIR` | `browser_profile/` vedle skriptu (persistent Chromium profil) |
| `STUDY` | `36940` (interní study ID pro 77242113UCO3001) |
| `SITE_IDS` | seznam 12 interních čísel center — viz níže |
### Interní čísla center (SITE_IDS)
```
930551, 930556, 930525, 930549, 930543, 930547,
930555, 930557, 930539, 930536, 930553, 930531
```
> **Zdroj:** převzato z `download_equeries_report_v1.1.py` (proměnná `SITES`).
> Jsou to **interní ID** Labcorpu, **nikoli** čísla center typu CZ10001.
> V URL test-results se používá právě toto interní ID:
> `…/test-results/{SITE_ID}/standard-test-results`.
### Generování REPORTS (DRY)
`REPORTS` se sestaví automaticky z `SITE_IDS` — URL i název souboru mají vzor
napsaný jen jednou. **Přidání/odebrání centra = úprava seznamu `SITE_IDS`.**
---
## 4. Výstupní soubory
Formát názvu (timestamp + popisný název):
```
{YYYY-MM-DD_HHMMSS} sponsor-study-36940-test-results-{SITE_ID}-standard.csv
```
Příklad:
```
2026-05-29_125710 sponsor-study-36940-test-results-930557-standard.csv
```
- Timestamp se generuje pro **každý** report zvlášť (v okamžiku exportu).
- Staré soubory se **nikdy nemažou** (verzování přes timestamp).
- Browser dočasný název se na disk neukládá — `expect_download` zachytí download
event a `save_as()` ho uloží pod naším názvem.
---
## 5. Průběh skriptu (kroky + logging)
Každý krok se loguje s časem (`[HH:MM:SS]`, `flush=True` → vypisuje průběžně).
| Fáze | Co dělá |
|---|---|
| START | spustí prohlížeč |
| LOGIN | otevře login; **pokud je session aktivní, přihlášení přeskočí** |
| Pro každé centrum: | |
| KROK 1/5 | navigace na report URL |
| KROK 2/5 | čeká na řádky gridu `.ag-row` **nebo** prázdný grid; pak stabilizace počtu |
| KROK 3/5 | klik na viditelné tři tečky (`more_horiz`) → otevře menu |
| KROK 4/5 | klik na viditelné „Export to CSV" → zachytí download |
| KROK 5/5 | uloží soubor do `OUT_DIR` |
| KONEC | souhrn `hotovo X/12` + seznam selhaných center |
### Příklad výstupu
```
[12:56:35] START: prohlizec spusten.
[12:56:35] LOGIN: otviram login stranku...
[12:56:49] LOGIN: prihlaseni OK (...)
[12:56:49] === Centrum 930557 (studie 36940) ===
[12:56:59] KROK 1/5: stranka nactena (...)
[12:57:05] KROK 2/5: radky se objevily, cekam na stabilizaci poctu...
[12:57:06] ...kontrola #1: 153 radku
[12:57:08] ...kontrola #2: 153 radku
[12:57:10] KROK 2/5: data stabilni (153 radku v gridu).
[12:57:10] KROK 3/5: menu otevreno.
[12:57:11] KROK 4/5: stahovani zachyceno, ukladam soubor...
[12:57:11] KROK 5/5: HOTOVO -> ...\2026-05-29_125710 sponsor-study-36940-test-results-930557-standard.csv
```
---
## 6. Klíčové technické poznatky (PROČ to tak je) — ověřeno přes Chrome DevTools
Stránka test-results je **Angular SPA** s knihovnou **MDL** a tabulkou **AG Grid**.
Tyto detaily byly zjištěny živou inspekcí DOM (Claude in Chrome MCP), ne hádáním:
### 6.1 Čekání na data = řádky AG Gridu
- Grid je `<covance-ag-grid>``<ag-grid-angular>` (AG Grid).
- Data jsou načtena, jakmile se objeví řádky **`div.ag-row`** (count jde z 0 → N;
pro 930557 to bylo 153 řádků).
- **Řádky jsou `position-absolute`** (virtuální render AG Gridu) → Playwright je
**nepovažuje za „visible"**. Proto:
-`wait_for_selector("div.ag-row")` (default `state="visible"`) **timeoutuje**
i když řádky existují.
- ✅ čekat na **přítomnost v DOM**:
`wait_for_function("() => document.querySelectorAll('div.ag-row').length > 0")`.
- Stabilizace: počet řádků se čte opakovaně co 2 s, dokud se 2× po sobě neshodne.
### 6.2 „Fetching Data" / spinner — POZOR, NEPLATÍ pro tuto stránku
- Na test-results stránce **NENÍ** text „Fetching Data" (ten je na *samples*
reportu, jiná stránka!).
- Je tu element `<loading-bar>`, ale ten jen krátce problikne `<mdl-progress>`
při route-loadingu, **ne** během načítání dat gridu → nelze na něj spoléhat.
- Spolehlivý signál je výhradně **objevení `.ag-row`**.
### 6.3 Tři tečky (export) — na stránce jsou DVA `<ag-export>`
- Na stránce existují **2× `<ag-export>`**: jeden **skrytý**, jeden viditelný.
- Existují **3× ikona `more_horiz`**: 1 mimo export (toolbar), 1 ve skrytém
ag-export, 1 ve viditelném.
- Proto je nutný filtr na viditelnost:
`page.locator("ag-export button:visible", has_text="more_horiz").first.click()`
### 6.4 „Export to CSV" — v DOM jsou DVĚ položky
- Po otevření menu existují **2× `mdl-menu-item` „Export to CSV"** (jedna skrytá
z neviditelného ag-export, jedna viditelná). Stejně tak 2× „Export to Excel".
- Proto:
`page.locator("mdl-menu-item:visible", has_text="Export to CSV").first.click()`
-`get_by_text("Export to CSV")`**strict mode violation** (2 elementy).
### 6.5 Prázdné centrum (ověřeno přes Chrome MCP na centru 930551)
- AG Grid při 0 záznamech zobrazí no-rows overlay s textem **„No Data"**.
- Struktura: `.ag-overlay``.ag-overlay-panel`
**`.ag-overlay-no-rows-wrapper`** → `<span>No Data</span>`.
- ⚠️ Třída **NENÍ** `.ag-overlay-no-rows-center` (to byl chybný předpoklad,
na který detekce nikdy nezabrala) — správně je **`.ag-overlay-no-rows-wrapper`**.
- ⚠️ Text „No Data" **NENÍ** v `.ag-body-viewport` (ten je prázdný,
`height: 1px`) — je v samostatném overlay sourozenci.
- ⚠️ Na stránce jsou **2 overlaye** (jeden skrytý, jeden viditelný) — stejně
jako u `ag-export`. Proto kontrola **viditelnosti** `offsetParent !== null`.
- Detekce (KROK 2):
```js
() => {
if (document.querySelectorAll('div.ag-row').length > 0) return false;
return [...document.querySelectorAll('.ag-overlay-no-rows-wrapper')]
.some(e => e.offsetParent !== null);
}
```
- KROK 2 čeká na `.ag-row` **NEBO** tuto detekci → centrum bez dat
necheká zbytečně 120 s a export se přeskočí.
---
## 7. Login logika (sdílená napříč Covance skripty)
```python
page.goto(LOGIN_URL)
page.wait_for_load_state("networkidle")
if not page.get_by_label("Email").is_visible():
return # session aktivní → login přeskočit
# jinak: Email → Next → Password → Verify → wait redirect (code= zmizí z URL)
```
- **Proč `is_visible()` a ne kontrola URL:** po `goto(LOGIN_URL)` zůstane URL
`xsp.covance.com` i po redirectu na dashboard, takže URL test je nespolehlivý.
Spolehlivé je, zda **existuje pole Email** (login formulář) nebo ne.
- `is_visible()` neháže výjimku — když pole není, vrátí `False`.
---
## 8. Chrome flagy proti „Restore pages" / broken session
V `args` launchu:
```
--disable-restore-session-state # neobnovovat předchozí session
--disable-session-crashed-bubble # potlačit "Chromium didn't shut down correctly"
```
Důvod: při natvrdo ukončeném skriptu (kill) Chromium jinak při dalším startu
nabídne „Restore pages?" dialog, který rozbil interakci.
---
## 9. Robustnost smyčky
- Každé centrum je v `try/except` → **chyba u jednoho nezastaví zbytek**.
- Na konci souhrn: `hotovo X/12` + seznam `SELHALA centra: …`.
- Selhané centrum v logu = snadno se dohledá a vyřadí/opraví ID.
---
## 10. Možná budoucí rozšíření
- **Microbiology záložka**: existuje i `…/test-results/{SITE}/microbiology…`
(analogická stránka, pravděpodobně stejná AG Grid logika).
- **Druhá studie** (MDD3003, study 35472): přidat další `STUDY` + `SITE_IDS`
a obalit do vnější smyčky (vzor viz `download_samples_report` se seznamem STUDIES).
- **Ověření počtu**: počet `.ag-row` se loguje — dá se porovnat s počtem řádků
ve staženém CSV jako sanity check.
---
## 11. Příbuzné skripty (stejná složka / portál)
| Skript | Co stahuje |
|---|---|
| `download_samples_report_v1.1.py` | All Samples (sampletracking, čeká na „Fetching Data") |
| `download_kit_inventory_v2.1.py` | Kit inventory (on-hand expiration) |
| `download_equeries_report_v1.1.py` | eQuery reporty (zdroj SITE_IDS) |
| `download_test_results_v1.0.py` | **tento** — Standard Test Results |
Všechny sdílejí: persistent profile, login logiku s `is_visible()` checkem,
`ag-export` + „Export to CSV" pattern (equeries/test-results).