# Payer portal downloader - ops handover Version: not versioned (no version number exists yet, see section 10) · Written 2026-10-23 · Escalation: RPA dev team, Teams channel **#rpa-support** ## 1. What the bot does Every day at 07:00 Windows Task Scheduler starts the bot. It signs in to the payer web portal in Chrome and downloads each provider's remittance report as a CSV file. Its input is the Excel workbook `data/input/providers.xlsx`, which has two sheets: **Login** (the portal username and password) and **Providers** (one provider per row). It produces three things: one CSV per provider in `data/downloads/`, a daily result workbook `data/output/Download_Report_.xlsx` with one row per provider, and screenshots of pages that failed to load in `data/screens/`. The only thing it drives is the payer portal, in a Chrome window it opens itself. ## 2. How it works ``` Windows Task Scheduler (07:00 daily) └─ starts → the bot (no window of its own) │ ├─ opens and drives → Chrome ("controlled by automated test software") │ └─> payer web portal: sign-in page, then each provider's remittance page │ (do not touch this Chrome window while it runs) ├─ reads → data/input/providers.xlsx (sheets Login, Providers) ├─ writes → data/downloads/*.csv (one file per provider, portal's own file name) ├─ writes → data/screens/.png (only when a page did not load) ├─ writes → data/output/Download_Report_.xlsx (saved at the END of the run) └─ writes → logs/bot.log (one line per provider) ``` - **Task Scheduler** is the only thing that starts the bot. The bot has no screen and no Start/Stop buttons. - **The bot** runs in the background, works through the providers one at a time from top to bottom, and closes Chrome when it finishes. - **Chrome** is opened by the bot. A bar at the top says it is controlled by automated software. That window belongs to the bot. - **The payer portal** is the website the bot signs in to and downloads from. - **providers.xlsx** is the input that ops maintains. - **data/downloads** holds the downloaded CSV files. They keep the portal's own file names, so a file name does not tell you which provider it belongs to. - **data/screens** holds a picture of the page for each provider whose report table did not load. - **Download_Report_.xlsx** is the result of the run. It is written only once, when the run ends. - **logs/bot.log** gets one line per provider giving the time, the NPI, the name and the status. It also gets a warning line every time the bot has to sign in again. **One run, step by step:** 1. Read the Login and Providers sheets. 2. Open Chrome and sign in to the portal. The bot waits up to 30 s for the portal's dashboard. 3. For each provider row: - If column C is `N`, skip it. - Otherwise open that provider's remittance page. - If the portal has signed the bot out, sign in again and retry, up to 3 tries in total. - Wait up to 30 s for the report table. - If the portal says there are no results, record "No Data". - Otherwise click the export button and wait up to 60 s for a new CSV file to appear. 4. Write one line to the log and one row in the report. 5. Close Chrome and save the report workbook. ## 3. Before a run - [ ] The machine has Google Chrome installed, and Python with the bot's packages installed. If either is missing the bot stops at start and no report is created (E09). - [ ] These folders exist in the bot folder: `data/input`, `data/output`, `data/downloads`, `data/screens` and `logs`. The bot does not create them. - If `data/output` is missing, the whole day's report is lost at the end of the run. - If `data/screens` is missing, no screenshots are saved, and nothing tells you so. - If `logs` is missing, the bot does not start. - [ ] `config.yaml` is in the bot folder. Do not edit it. - [ ] `data/input/providers.xlsx` exists and has sheets named exactly **Login** and **Providers**. - [ ] **Login** sheet: cell A2 holds the portal username and B2 the password. When the portal password changes, update B2 before the next 07:00 run, or every row comes out "Login Failed" (E01). - [ ] **Providers** sheet: row 1 is the header and data starts at row 2. Column A is the NPI, column B the provider name and column C the active flag. Rules for these columns: - **Column A (NPI) must not be blank.** A row with a blank column A is ignored without any message and gets no row in the report (E10). - Bad: blank A, name in B. - Good: `1234567890` in A. - **Column C: only a capital `N` means inactive.** `n`, `No` or `no` are treated as active, and the bot will try to download those providers. - Bad: `No`. - Good: `N`. Leave C blank for active providers. - [ ] A report for today already in `data/output` will be **overwritten** if the bot runs again today. Copy it somewhere first if you need to keep it. - [ ] There is no version number to check. See section 10. ## 4. During a run - Do not click, type in or close the Chrome window marked "controlled by automated test software". Do not sign in to the portal with the same username in another browser during the run, because the portal may sign the bot out. - You can use other programs on the machine. The bot does not need the mouse or keyboard. - **To stop the bot:** close the bot's Chrome window. The bot then stops, and the report is still saved for the providers it had finished; the rest get no row. Do **not** use "End" in Task Scheduler. That stops the bot without saving any report, and can leave Chrome open. - A run looks stuck when `logs/bot.log` gets no new line for 10 minutes. No single wait in the bot is longer than 60 s, but the bot has **no watchdog of its own**: it never restarts or gives up by itself. If it is stuck, stop it as described above and escalate (E03). ## 5. Where to look when something goes wrong | Question | Where to look | |---|---| | Did the run finish? | `data/output/Download_Report_.xlsx` exists, and it has one row for every provider in the input that has an NPI. Fewer rows means the run stopped partway (E03). No file at all means it never got going or lost the report (E09). | | Which providers failed? | The report workbook, **Status** column: red **Error**, or **Login Failed** (no colour). Also check every **Downloaded** row whose Remarks say "portal maintenance - no file". Those failed too, even though they are green (E04). | | Why did one provider fail? | The report workbook, **Remarks** column. For "Report grid did not load", open `data/screens/.png`. The log `logs/bot.log` shows only the time and the status. It does not record the reason. | | Did the bot already retry? | `logs/bot.log`: lines with "session expired, re-login 1" (or 2, 3) just before that provider's line. Sign-in after the portal signs the bot out is the only thing the bot retries. | | Which CSV belongs to which provider? | There is no reliable way. The files in `data/downloads` keep the portal's names. They can only be matched by file time against the log line times. | | Which version is running? | No version is shown anywhere (section 10). | ## 6. Statuses All statuses appear in the report workbook's **Status** column, with the reason in **Remarks**. | Status - Remarks | Colour | Meaning | What ops does | |---|---|---|---| | Downloaded - "Report saved" | green | A new CSV appeared in `data/downloads` | Nothing. See E07 for one rare case where the file belongs to the previous provider. | | Downloaded - "portal maintenance - no file" | green | **Not downloaded.** The portal showed a maintenance notice, and the bot recorded it as Downloaded. **Needs follow-up.** | Re-run after the maintenance window (E04) | | No Data - "No remittances in the date range" | green | The portal shows no remittances for this provider | Nothing, unless you expected remittances (E06) | | Skipped - inactive provider - "Marked N in the input" | green | Column C was `N`, so the bot did not try | Nothing, unless the provider is active again. Then clear column C. | | Error - "Report grid did not load" | red | The report table did not appear within 30 s. A screenshot was saved. | E05 | | Error - "Download did not finish" | red | No new CSV appeared within 60 s of clicking export | E07 | | Error - "Session expired" | red | The portal signed the bot out 3 times in a row on this provider | E02 | | Login Failed - "Check the portal username/password" | **no colour** (white) | The first sign-in failed. Every provider gets this row and nothing is downloaded. | E01 | | *(no row for a provider)* | - | Either its NPI cell is blank (E10), or the run stopped before reaching it (E03) | See E10 / E03 | ## 7. Exception catalogue | ID | What you see | How the bot identifies it | Where it is recorded | Type | Who acts | What to do | Escalate when | |---|---|---|---|---|---|---|---| | E01 | Every row is "Login Failed - Check the portal username/password" | After signing in, it waits 30 s for the portal dashboard. If the dashboard never appears, it gives up and nothing is downloaded. | Report workbook only. **Nothing is written to the log.** | Business (wrong password) or System (portal slow or down) | Ops | Sign in to the portal by hand with the Login sheet's A2/B2 values. If that fails, fix the password in B2. If it works, the portal was slow: run the bot again. | Manual sign-in works but the bot fails twice in a row. Send: date, report file, "E01". | | E02 | Error - "Session expired" | The provider's page sends the bot back to the sign-in page. It signs in again and retries, up to 3 tries in total. | Report workbook; "session expired, re-login N" lines in `logs/bot.log` | System | Bot, then Ops | Re-run the bot later. Check that nobody else was using the same portal login at that time. | Several providers in the same run, or on 2 days in a row. Send: date, log time of the warnings, "E02". | | E03 | The report has fewer rows than the input, and the rows stop at some provider | Not detected. An unexpected problem stopped the bot. Possible causes: the portal's sign-in failed while signing back in; a button or field it needs was missing on the page; Chrome was closed or crashed; the run was stopped by hand. | Nothing. The report is saved with the rows done so far. **The log has no error line.** | System | Dev | Note the first provider that is missing, then run the bot again. A same-day re-run overwrites the report, so copy the partial report first. | Always, unless you stopped it yourself. Send: date, the partial report, the first missing provider's row number in the input, the last time in `logs/bot.log`, "E03". | | E04 | **Green** "Downloaded" with Remarks "portal maintenance - no file" | The provider's page shows the portal's maintenance notice. The bot records it as Downloaded and moves on. | Report workbook (green); the log says "Downloaded" | System | Ops | Treat it as **not downloaded**. Check the portal's maintenance window and run the bot again after it. | The notice is still there after the portal says maintenance is over. Send: date, "E04". | | E05 | Error - "Report grid did not load" | It waits 30 s for the provider's report table. If it never appears, it saves a screenshot and moves on. | Report workbook; `data/screens/.png` | System | Ops | Open the screenshot. If it shows a slow or blank page, run the bot again later. If it shows an error message from the portal, follow that message. | The same provider fails on 2 runs, or the screenshot shows the page looking different from usual. Send: date, the screenshot, "E05". | | E06 | No Data - "No remittances in the date range" | The portal shows its "no results" message for that provider | Report workbook (green) | Business | Ops | Usually nothing. If you expected remittances, check the provider in the portal by hand, and check the NPI in column A. | You see remittances in the portal by hand but the bot says No Data. Send: date, "E06". | | E07 | Error - "Download did not finish" | After clicking export, it checks `data/downloads` every second for 60 s for a new CSV file. If none appears, it moves on. | Report workbook | System | Ops | **Check `data/downloads` first.** The file may have arrived late. A late file can also be counted as the *next* provider's download, so that provider's "Downloaded" may be wrong. If no late file is there, run the bot again. | It happens for several providers in one run, or on 2 days in a row. Send: date, log times, "E07". | | E08 | "Skipped - inactive provider" for a provider you expected | Column C of its row is exactly `N` | Report workbook (green) | Business | Ops | Clear column C if the provider is active. | Never. This is an input fix. | | E09 | No report file for today in `data/output` | Not detected. Possible causes: the bot never started (missing `logs` folder, missing `config.yaml`, missing input file, Chrome or Python problem, often after a Chrome update); or the `data/output` folder is missing so the report could not be saved. | Nothing. Check whether `logs/bot.log` has lines for today. | System | Ops, then Dev | Check the folders and files in section 3. If they are all there, escalate. | The folders and input are fine and there is still no report. Send: date, whether `logs/bot.log` has lines for today, "E09". | | E10 | A provider from the input has no row in the report, but the providers after it do | Rows with a blank NPI (column A) are ignored without a message | Nothing | Business | Ops | Fill in the NPI in column A. | Never. This is an input fix. | ## 8. What the bot recovers by itself | Problem | What the bot does | Limit | After the limit | |---|---|---|---| | The portal signs the bot out | Signs in again and opens the provider's page again | 3 tries per provider | Row = Error "Session expired", next provider. If signing in again itself fails, the run stops (E03). | | First sign-in slow | Waits for the dashboard | 30 s, **no retry** | Every row "Login Failed", run ends | | Report table slow | Waits | 30 s, **no retry** | Row = Error "Report grid did not load", screenshot, next provider | | CSV download slow | Checks every second | 60 s, **no retry** | Row = Error "Download did not finish", next provider | | Anything else (a missing button, Chrome crash, stuck page) | Nothing. No restart, no watchdog, no resume. | - | The run stops. The report is saved with the rows done so far (E03). | A re-run always starts again from the first provider. It downloads every provider again (duplicate CSVs in `data/downloads`) and overwrites today's report and screenshots. ## 9. Known incidents There is no recorded history: no version control, changelog or bug log was found. The only evidence is `logs/bot.log`, which covers one run on 2026-09-02. | When / version | What ops saw | Cause | What to do now | Ops could handle? | |---|---|---|---|---| | 2026-09-02 / not versioned | One provider re-logged in once ("session expired, re-login 1"); one provider ended in Error | The log records no reason for the Error, so the cause is unknown | Read the Remarks column in that day's report, then use E02/E05/E07 | Partly. The log alone cannot tell you which Error it was. | ## 10. Releases and version check - How an update arrives: there is no updater. A developer replaces the bot's files on the machine by hand. - How to confirm it applied: there is no version number in the bot. Ask the dev team in #rpa-support to confirm what changed. - If something stops working after an update: escalate with the date of the change. Chrome updates itself. If the bot suddenly stops starting the day after a Chrome update (E09), say so in the ticket. - Only one machine runs this bot, through Task Scheduler. Do not set it up on a second machine. Two runs on the same day overwrite each other's report. ## 11. Escalating to dev Post in the Teams channel **#rpa-support**. Send: - the date of the run - the exception ID from section 7 (E01-E10) - the report workbook from `data/output` - the relevant time from `logs/bot.log` - the screenshot from `data/screens` (for E05) - for one provider, its **row number** in the input Never send in chat: the portal password, the input workbook (it contains the password), `config.yaml`, or provider names and NPIs. ## 12. Failure-class check - **F1** (missing prerequisite) is covered in section 3 (Chrome, Python, folders, `config.yaml`, input sheets) and E09. - **F2** (wrong window or focus) is covered in section 4: do not touch the bot's Chrome window. Matching windows by title and taking focus are not applicable, because the bot controls its own Chrome directly, not through screen clicks. - **F3** (target app slower or different than expected) is covered in E01, E05 and E07, and section 8 (30 s and 60 s waits, no retry). The fixed waits with no retry are in Fix before handover #9. - **F4** (input read differently than written) is covered in section 3 (blank NPI, capital `N` only, sheet names) and E08 and E10. Fix before handover #8. - **F5** (marked done when nothing was done) is covered in E04: maintenance is recorded as Downloaded. Fix before handover #1 and #4. - **F6** (action happened but could not be confirmed) is covered in E07: check `data/downloads` before re-running, because a late file can arrive and be counted as the next provider's. Fix before handover #4. - **F7** (business exception shown as success) is covered in section 6 and E04: the maintenance row is green. "Login Failed" has no colour. Fix before handover #1 and #6. - **F8** (endless re-runs or watchdog kills): an endless loop is not applicable, because the bot has no auto-rerun and no watchdog, and the sign-in retry stops at 3. The missing watchdog is covered in section 4 (stuck sign) and section 8. - **F9** (stopping the bot the wrong way) is covered in section 4: close the bot's Chrome window, not End in Task Scheduler. Fix before handover #11. - **F10** (one stuck item blocks the queue): a queue lock is not applicable, because there are no batches or locks. One crash does stop all remaining providers, which is covered in E03 and Fix before handover #2. - **F11** (cause hidden from ops) appears in Fix before handover #3, #4 and #5: crash details are not logged, remarks are not logged, and CSV names do not identify the provider. - **F12** (update did not arrive, or an old build undid a new one) is covered in section 10. Fix before handover #10. Rewriting shared resources on start is not applicable, because the bot writes nothing shared on start. ## 13. Fix before handover (dev team) | # | Gap | Why it hurts ops | Where (file:line) | |---|---|---|---| | 1 | The maintenance banner returns status "Downloaded" (green) although no file was downloaded | Ops thinks the provider is done. The report is missing and nobody follows up. | `bot.py:54-55` | | 2 | Unexpected errors are not caught: a failed re-login (`login()` raises `RuntimeError`), `NoSuchElementException` from `find_element`, a WebDriver crash or a missing sheet `KeyError`. The run stops, and the remaining providers get no row. There is also a pointless extra re-login after the 3rd `SessionExpired`. | One problem stops the whole day's downloads, with no message saying why | `bot.py:41-43`, `:64`, `:77`, `:96-104`, `:108-110` | | 3 | No exception or traceback is logged. The first-login failure is not logged. Under Task Scheduler, stderr is lost. | E01, E03 and E09 leave no trace for ops or dev | `bot.py:30-31`, `:86-91`, `:113-114` | | 4 | Download detection counts *any* new `*.csv`, so a late file from the previous provider is credited to the current one. The files are not renamed to the NPI. | A wrong "Downloaded" is possible, and ops cannot tell which CSV belongs to which provider | `bot.py:63-68` | | 5 | The log line has no remark (status only) | The log cannot explain an Error | `bot.py:105` | | 6 | "Login Failed" rows get no colour: `ws.append` at the first-login path skips the fill | The failure is not red like other failures | `bot.py:88-90` | | 7 | Folders are never created. A missing `data/output` fails the final save and loses the whole report. A missing `data/screens` makes `save_screenshot` return False silently. A missing `logs` fails at import. | Silent loss of the report or screenshots on a fresh machine | `bot.py:20-21`, `:30`, `:59`, `:110` | | 8 | Only an exact uppercase `"N"` counts as inactive. Rows with a blank NPI are dropped without a message. | Input mistakes are silent | `bot.py:77-78` | | 9 | Login, grid and download waits are fixed (30 s / 30 s / 60 s) with no retry. The login wait reuses `GRID_WAIT_S`. | A slow portal morning becomes a day of Errors, or "Login Failed" on every row | `bot.py:22-23`, `:44-47`, `:56-60`, `:65-70` | | 10 | No version string. `requirements.txt` has no pinned versions. | Ops cannot confirm an update, and a package upgrade can break the bot without warning | `bot.py` (none), `requirements.txt:1-3` | | 11 | No safe stop. Ending the task in Task Scheduler skips the `finally` block, so there is no report and Chrome may be left open. | The only safe stop is closing Chrome, which is not obvious | `bot.py:108-110` | | 12 | A same-day re-run overwrites `Download_Report_.xlsx` and `data/screens/.png` | The first run's evidence is lost on re-run | `bot.py:59`, `:110` | | 13 | The portal password is stored in plain text in the input workbook (Login!B2) | Credential exposure every time the input is shared | `bot.py:76` | | 14 | `config.yaml` holds an `api_token` value that the code never uses | An unused secret on disk. Remove it, or rotate it if it is live. | `config.yaml` (key `api_token`) | | 15 | `BOT_WAS_RUN` marker file is written on every start, and nothing reads it | Ops may wonder what it is. Remove it, or document it. | `bot.py:74` |