Initial import: eCW Charge Validation bot and results Portal

Snapshot of the working project as of 2026-10-23 (local 2d4d4fc), one
commit with no earlier history: the tracked files were de-identified
first (synthetic claim ids and patient data only; see Context.md
section 7). Credentials, run logs, screenshots, claim reports and client
workbooks are gitignored and not included.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
ManikandanandClaude Opus 5.5 committed 2026-10-23 18:38:17 +05:30
commit ba15a574ab
205 files changed
+56772

No files matched your search

+126
View File
@@ -0,0 +1,126 @@
{% extends "base.html" %}
{% block title %}Run {{ run.run_id }}{% endblock %}
{% block head %}{% if run.status == "Running" %}<meta http-equiv="refresh" content="5">{% endif %}{% endblock %}
{% block style %}
.st { display: inline-block; padding: 2px 9px; border-radius: 10px;
font-weight: 600; font-size: 12px; background: var(--head); }
.st.Done { background: var(--pass-bg); color: var(--pass); }
.st.Run-Error, .st.Ended-without-a-record { background: var(--fail-bg);
color: var(--fail); }
.st.Stopped { background: var(--review-bg); color: var(--review); }
.st.Running { background: var(--hilite); color: var(--accent); }
dl.facts { display: grid; grid-template-columns: 150px 1fr; gap: 6px 12px;
margin: 0; }
dl.facts dt { color: var(--muted); }
dl.facts dd { margin: 0; }
.card.error { border-left: 5px solid var(--fail); }
.card.warn { border-left: 5px solid var(--review-bar); }
table.plain { width: 100%; border-collapse: collapse; font-size: 13px; }
table.plain th, table.plain td { text-align: left; padding: 6px 8px;
border-bottom: 1px solid var(--line);
vertical-align: top; }
table.plain th { color: #3b4757; font-size: 12px; text-transform: uppercase;
letter-spacing: .4px; background: var(--head); }
td.t { white-space: nowrap; color: var(--muted); width: 90px; }
.ok { color: var(--pass); font-weight: 600; }
.no { color: var(--fail); font-weight: 600; }
pre.tb { background: var(--head); padding: 10px; border-radius: 6px;
white-space: pre-wrap; font-size: 12px; margin: 6px 0 0; }
ul.claims { columns: 4; margin: 0; padding-left: 18px; }
tr.k-run_error td, tr.k-claim_error td { color: var(--fail); }
tr.k-warning td { color: var(--review); }
{% endblock %}
{% block content %}
<h1>Run {{ run.started | usdate }} <span class="st {{ run.status | replace(' ', '-') }}">{{ run.status }}</span></h1>
<p class="sub">{% if run.status == "Running" %}Still running — this page refreshes every 5 seconds.{% else %}Ran {{ run.duration_s | dur }}.{% endif %}</p>
<div class="card">
<dl class="facts">
<dt>Started By</dt><dd>{{ run.started_by }}</dd>
<dt>Source</dt><dd>{{ run.source | capitalize }}</dd>
<dt>Mode</dt><dd>{{ run.mode }}{% if run.test_sheet %} · claims from {{ run.test_sheet }}{% endif %}</dd>
<dt>Started</dt><dd>{{ run.started | usdate }}</dd>
<dt>Ended</dt><dd>{{ run.ended | usdate }}</dd>
<dt>Result</dt><dd>{{ run.status }}{% if run.exit_code is not none %} (exit {{ run.exit_code }}){% endif %}{% if run.error_step %} — {{ run.error_step }}: {{ run.error_message }}{% endif %}</dd>
{% if run.status == "Stopped" %}<dt>Stopped By</dt><dd>{{ run.stopped_by or "—" }}</dd>{% endif %}
<dt>Claims</dt><dd>{{ run.claims_done }} of {{ run.claims_total }} checked ·
{{ run.pass }} Pass · {{ run.fail }} Fail · {{ run.review }} Review{% if run.not_found %} · {{ run.not_found }} not found{% endif %}</dd>
</dl>
</div>
{% if run.run_errors %}
<div class="card error">
<h2>Run Error</h2>
{% for e in run.run_errors %}
<p><strong>{{ e.t[11:19] }}</strong> · {{ e.step }} · exit {{ e.exit_code }} — {{ e.message }}</p>
{% if e.traceback %}<details><summary>Traceback</summary><pre class="tb">{{ e.traceback }}</pre></details>{% endif %}
{% endfor %}
</div>
{% endif %}
<div class="card">
<h2>eCW Login Attempts{% if run.login_attempts %} · {{ run.login_total_s | dur }} in all{% endif %}</h2>
{% if run.login_attempts %}
<table class="plain">
<thead><tr><th>#</th><th>Start</th><th>End</th><th>Took</th><th>2FA mail wait</th><th>Result</th><th>Steps</th></tr></thead>
<tbody>
{% for a in run.login_attempts %}
<tr>
<td>{{ a.attempt }}</td>
<td>{{ a.start | usdate }}</td>
<td>{{ a.end | usdate }}</td>
<td>{{ a.duration_s | dur }}</td>
<td>{{ a.twofa_wait_s | dur if a.twofa_wait_s is not none else "—" }}</td>
<td class="{{ 'ok' if a.result == 'ok' else 'no' }}">{{ a.result_label }}{% if a.message %} — {{ a.message }}{% endif %}</td>
<td>{% for label, time in a.step_rows %}{{ time }} {{ label }}{% if not loop.last %}<br>{% endif %}{% endfor %}</td>
</tr>
{% endfor %}
</tbody>
</table>
{% else %}<p class="note">No eCW login in this run.</p>{% endif %}
</div>
{% if run.claim_errors %}
<div class="card error">
<h2>Claim Errors ({{ run.claim_errors | length }})</h2>
<p class="note">The bot could not check these claims; the Charge Summary shows them as Review.</p>
<table class="plain">
<thead><tr><th>Time</th><th>Claim</th><th>Step</th><th>Message</th></tr></thead>
<tbody>{% for e in run.claim_errors %}<tr><td class="t">{{ e.t[11:19] }}</td><td>{{ e.claim }}</td><td>{{ e.step }}</td><td>{{ e.message }}</td></tr>{% endfor %}</tbody>
</table>
</div>
{% endif %}
{% if run.not_reached %}
<div class="card error">
<h2>Not Reached ({{ run.not_reached | length }})</h2>
<p class="note">Queued, but the run ended before it got to them.</p>
<ul class="claims">{% for c in run.not_reached %}<li>{{ c }}</li>{% endfor %}</ul>
</div>
{% endif %}
{% if run.warnings %}
<div class="card warn">
<h2>Warnings ({{ run.warnings | length }})</h2>
<table class="plain">
<thead><tr><th>Time</th><th>Kind</th><th>Claim</th><th>Message</th></tr></thead>
<tbody>{% for e in run.warnings %}<tr><td class="t">{{ e.t[11:19] }}</td><td>{{ e.code }}</td><td>{{ e.claim or "" }}</td><td>{{ e.message }}</td></tr>{% endfor %}</tbody>
</table>
</div>
{% endif %}
{% if run.screenshots %}
<div class="card">
<h2>Failure screenshots</h2>
<ul>{% for e in run.screenshots %}<li>{{ e.t[11:19] }} <a href="/runs/{{ run.run_id }}/shot/{{ loop.index0 }}" target="_blank" rel="noopener">{{ e.tag }}</a></li>{% endfor %}</ul>
<p class="note">Each one's page HTML, when saved, is beside it in Screenshots\ (open it there, not here).</p>
</div>
{% endif %}
<div class="card">
<h2>Timeline</h2>
<table class="plain">
<tbody>{% for e in run.timeline %}<tr class="k-{{ e.kind }}"><td class="t">{{ e.time }}</td><td>{{ e.text }}</td></tr>{% endfor %}</tbody>
</table>
</div>
{% endblock %}