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

+106
View File
@@ -0,0 +1,106 @@
<!doctype html>
<!-- A claim form's side menu + eCW's Account Inquiry ("Patient Inquiry
Detail") modal, after the bindings in Dom.txt (2026-10-20). Made-up
claims only. A test sets window.HISTORY_PAGES (one array of claims per
page: {id, date, codes}) before clicking the launcher. The CPT rows are
loaded only once "Show CPT Payments" is ticked, as eCW reloads them. -->
<html><head><meta charset="utf-8"><title>Account Inquiry fixture</title>
<style>.ng-hide{display:none}.modal{display:none}.modal.in{display:block}</style>
</head><body>
<div class="claim-form" id="claimFormFixture">
<ul class="side-menu">
<li><a>UB Claim</a></li>
<li><a>Documents</a></li>
<li><a class="cursor" title="Account Inquiry" ng-click="vm.loadSmartPanel(item);" style="display:none"><label class="ft-label">Account Inquiry</label></a></li>
<li><a class="cursor" title="Documents" ng-click="vm.loadSmartPanel(item);"><label class="ft-label">Documents</label></a></li>
<li><a id="acctInq" class="cursor" title="Account Inquiry" ng-click="vm.loadSmartPanel(item);"><label class="ft-label">Account Inquiry</label></a></li>
<li><a>Actions</a></li>
</ul>
<button id="formCancel">Cancel</button>
</div>
<div class="modal" id="piModal">
<div class="modal-header">
<button type="button" class="close"
ng-click="validateandclosePatientInquiryDetailModal(false)">×</button>
<h4 class="modal-title">Patient Inquiry Detail</h4>
</div>
<div id="accountsLoadingImg" style="display:none">Loading…</div>
<div class="pull-left doc-att mt5">
<label class="checkbox-inline" ng-repeat="filter in collClaimFiltersFieldNames track by $index"><input type="checkbox" ng-model="filter.mod" ng-click="reloadClaimData($index,$event)" data-f="cpt"> Show CPT Payments</label>
<label class="checkbox-inline" ng-repeat="filter in collClaimFiltersFieldNames track by $index"><input type="checkbox" ng-model="filter.mod" ng-click="reloadClaimData($index,$event)"> Show CPT Payment Totals</label>
<label class="checkbox-inline" ng-repeat="filter in collClaimFiltersFieldNames track by $index"><input type="checkbox" ng-model="filter.mod" ng-click="reloadClaimData($index,$event)"> Show Voided Claims</label>
</div>
<div>
<button class="btn" ng-click="pibuttonprev()">PREV</button>
<input type="text" ng-model="curpage" id="pigoToPageNo" value="1">
of <span ng-bind="totalPage">1</span>
<button class="btn" ng-click="pibuttonnext()">NEXT</button>
</div>
<table class="table claimsDtlMainTbl"><tbody id="claims"></tbody></table>
<button class="btn" ng-click="validateandclosePatientInquiryDetailModal(true)">OK</button>
</div>
<script>
window.HISTORY_PAGES = window.HISTORY_PAGES || [[]];
let page = 0, showCpt = false;
const modal = document.getElementById('piModal');
const loader = document.getElementById('accountsLoadingImg');
const cptBox = document.querySelector('input[data-f="cpt"]');
function render() {
const pages = window.HISTORY_PAGES;
document.getElementById('pigoToPageNo').value = String(page + 1);
document.querySelector('[ng-bind="totalPage"]').textContent =
String(pages.length);
const body = document.getElementById('claims');
body.innerHTML = '';
for (const c of pages[page] || []) {
const cpt = showCpt ? c.codes.map(code =>
`<tr class="cptPaymentRow ng-scope" ng-repeat="charge in payment.Charges track by $index">` +
`<td></td><td ng-bind="getCPTPaymentDescription(charge,true)">${code}:SOME SERVICE…</td>` +
`<td ng-bind="charge.BilledFee">10.00</td></tr>`).join('') : '';
const tr = document.createElement('tr');
tr.setAttribute('ng-repeat', 'claim in claims track by $index');
tr.innerHTML =
`<td><table><tbody>` +
`<tr class="claimMainRow"><td ng-bind="claim.ClaimId">${c.id}</td>` +
`<td ng-bind="claim.ServiceDate | date:'MM/dd/yyyy'">${c.date}</td>` +
`<td ng-bind="getClaimDescription(claim,true)">Charges (Pr:XX Fac: YY)</td></tr>` +
`<tr class="claimChildRow0" ng-repeat="payment in claim.Payments track by $index">` +
`<td><table><tbody><tr><td>Medicare</td></tr>${cpt}</tbody></table></td></tr>` +
`</tbody></table></td>`;
body.append(tr);
}
}
function loading(then) {
loader.style.display = 'block';
setTimeout(() => { then(); loader.style.display = 'none'; }, 300);
}
document.getElementById('acctInq').addEventListener('click', () => {
if (window.NO_INQUIRY) return;
page = 0;
setTimeout(() => { modal.classList.add('in'); loading(render); }, 200);
});
cptBox.addEventListener('click', () => {
showCpt = cptBox.checked;
loading(render);
});
document.querySelector('[ng-click="pibuttonnext()"]').addEventListener(
'click', () => {
if (page < window.HISTORY_PAGES.length - 1) { page++; loading(render); }
});
document.querySelector(
'button.close[ng-click="validateandclosePatientInquiryDetailModal(false)"]')
.addEventListener('click', () => {
if (window.STUCK_OPEN) return;
window.CLOSED_WITH = 'X';
modal.classList.remove('in');
});
document.querySelector(
'[ng-click="validateandclosePatientInquiryDetailModal(true)"]')
.addEventListener('click', () => { window.CLOSED_WITH = 'OK'; });
</script>
</body></html>
+208
View File
@@ -0,0 +1,208 @@
<!doctype html>
<!--
A cut-down of eCW's Dental Claim screen (mapped from live claim 9125000 —
DentaQuest; the claim number, patient and account here are made up). A THIRD claim-form shape, distinct from both the UB form and
the professional/HCFA "Claim" screen: its own modal entirely
(id="dentalClaim<timestamp>"), closeDntl() instead of
closeUBClaimScreen()/closeClaimScreen(), saveData() instead of
saveAllData(true)/saveAllData(), and a completely different tab set
("ICD & CDT" / "Services Rendered" rather than "ICD & CPT" / "CPT/HCPCS").
Since 2026-10-12 Dental claims run the same conditions as UB/HCFA, so
this fixture carries the screen's real shapes (from Dom.txt's capture):
the Services Rendered grid, the ICD list, the insurance grid, the Billing
Notes and the Prog. Notes button — see the comments on each. The claim
number and the web_cptcode inputs are also what
claim_form.wait_claim_loaded() watches (review item D7). Codes are
generic CDT/CPT codes; nothing comes from a real claim. Every id carries the per-open timestamp 7777777777777,
deliberately different from both hcfa_claim.html's 8888888888888 and
ub_claim.html's 9999999999999.
-->
<html>
<body>
<div class="modal fade bluetheme billing-width dentalClaimModalBackdrop right-panel-mode in" id="dentalClaim7777777777777" style="display:block">
<div class="modal-dialog visible" style="width: 1286px;">
<div class="modal-content" id="dentalClaimModalContent7777777777777">
<div class="modal-header">
<h4 class="modal-title">Dental Claim
<span class="ml5 fs11 patient-identifier-span">TESTPATIENT, Demo &nbsp; Jan 01, 1970 (56 yo F) &nbsp; Acc No. 000000</span>
</h4>
</div>
<div class="modal-body">
<table class="table"><tbody><tr>
<td><label>Claim No</label></td>
<td><span ng-bind="ClaimData.claimNo">5000000</span></td>
</tr></tbody></table>
<!--
"Services Rendered" (2026-10-12, Dental claims run the conditions):
the live grid's shape from Dom.txt — rows are
tr[ng-repeat="CPT in CPTCodes track by $index"], no CPTROW_ id; the
fields go by data-fieldname (web_cptcode, web_icd1-4, web_units,
web_billedFee); the checkbox is the same updateBillToIns() one as
UB/HCFA. No per-row POS and no modifier columns. The trailing "new
code" row has no data-fieldname. Codes are generic CDT/CPT codes, fees
made up.
-->
<table id="claimCPTCodesTable7777777777777" class="table">
<thead><tr>
<th></th><th>&nbsp;</th><th>Tth No</th><th>Srfc</th>
<th>Description of Service Performed</th><th>DOS</th><th>Proc No</th>
<th>ICD1</th><th>ICD2</th><th>ICD3</th><th>ICD4</th><th>Units</th>
<th>Fee</th><th></th>
</tr></thead>
<tbody ng-model="CPTCodes">
<tr ng-repeat="CPT in CPTCodes track by $index">
<td>1</td>
<td><input type="checkbox" id="claimCPTBillToInsChk0" ng-click="updateBillToIns($index)" checked></td>
<td id="TthNo0"></td><td></td><td>PERIODIC ORAL EVALUATION</td>
<td><input id="DentalClaimCPTSDOS0" data-fieldname="DentalClaimCPTSDOS" type="text" value="09/01/2026"></td>
<td><input id="dentalClaimCPTCode0" data-fieldname="web_cptcode" type="text" value="D0120"></td>
<td><input id="dentalClaimIcd10" data-fieldname="web_icd1" type="text" value="1"></td>
<td><input id="dentalClaimIcd20" data-fieldname="web_icd2" type="text" value=""></td>
<td><input id="dentalClaimIcd30" data-fieldname="web_icd3" type="text" value=""></td>
<td><input id="dentalClaimIcd40" data-fieldname="web_icd4" type="text" value=""></td>
<td><input id="DentalClaimCPTUnits0" data-fieldname="web_units" type="text" value="1"></td>
<td><input id="DentalClaimIpt1ngR0" data-fieldname="web_billedFee" type="text" value="45.00"></td>
<td><button id="DentalClaimBtn1ngR0" ng-click="removeCPT($index)"></button></td>
</tr>
<tr ng-repeat="CPT in CPTCodes track by $index">
<td>2</td>
<td><input type="checkbox" id="claimCPTBillToInsChk1" ng-click="updateBillToIns($index)" checked></td>
<td id="TthNo1"></td><td></td><td>DENTAL CONSULT</td>
<td><input id="DentalClaimCPTSDOS1" data-fieldname="DentalClaimCPTSDOS" type="text" value="09/01/2026"></td>
<td><input id="dentalClaimCPTCode1" data-fieldname="web_cptcode" type="text" value="DCONS"></td>
<td><input id="dentalClaimIcd11" data-fieldname="web_icd1" type="text" value="1"></td>
<td><input id="dentalClaimIcd21" data-fieldname="web_icd2" type="text" value=""></td>
<td><input id="dentalClaimIcd31" data-fieldname="web_icd3" type="text" value=""></td>
<td><input id="dentalClaimIcd41" data-fieldname="web_icd4" type="text" value=""></td>
<td><input id="DentalClaimCPTUnits1" data-fieldname="web_units" type="text" value="1"></td>
<td><input id="DentalClaimIpt1ngR1" data-fieldname="web_billedFee" type="text" value="30.00"></td>
<td><button id="DentalClaimBtn1ngR1" ng-click="removeCPT($index)"></button></td>
</tr>
<tr>
<td></td><td></td><td></td><td></td><td></td><td></td>
<td ng-click="enterCPT($event)"><input type="text" id="editableTDTextNewCPTcode" ng-model="newCPT"></td>
<td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
</tbody>
</table>
<!-- "ICD & CDT": the diagnosis list (#icdTable #addTable on the live screen) -->
<div class="allbrd white-bg icdTbl" id="icdTable">
<table class="table" id="addTable">
<thead><tr><th></th><th>Code</th><th>Name</th><th></th></tr></thead>
<tbody ng-model="ICDData">
<tr ng-repeat="ICDCode in ICDData">
<td>1</td>
<td ng-click="enterICD($event)"><input type="text" value="Z01.20"></td>
<td>Encounter for dental exam</td>
<td><button id="DentalClaimBtn2ngR0" ng-click="removeICD($index)"></button></td>
</tr>
<tr id="2">
<td></td>
<td ng-click="enterICD($event)"><input type="text" id="txtnewIcd7777777777777"></td>
<td></td><td></td>
</tr>
</tbody>
</table>
</div>
<!-- Insurance (#DentalClaimTbl2 on the live screen) -->
<table id="DentalClaimTbl2" class="table">
<thead><tr>
<th></th><th>Bill To</th><th>Ins Id</th><th>Name</th><th>State</th>
<th>Subscriber No</th><th>Rel</th><th>Insured</th><th>Group No</th>
</tr></thead>
<tbody>
<tr ng-repeat="insurance in Insurances">
<td><span ng-bind="insurance.sequanceNo">P</span></td>
<td><input id="DentalClaimIpt20ngR0" type="checkbox" ng-model="insurance.PrimIns" checked></td>
<td><span ng-bind="insurance.InsId">1001</span></td>
<td><span ng-bind="insurance.InsName">DentaQuest</span></td>
<td><span ng-bind="insurance.InsState">CO</span></td>
<td><span ng-bind="insurance.SubscriberNo">X000000</span></td>
<td><span ng-bind="insurance.SubscriberRel">Self</span></td>
<td><span ng-bind="insurance.SubscriberName">TESTPATIENT, Demo</span></td>
<td><span ng-bind="insurance.GroupNo"></span></td>
</tr>
</tbody>
</table>
<textarea id="dentalClaimNotes">Routine visit.</textarea>
</div>
<div class="modal-footer grey-bg claimOptionMenu">
<button type="button" class="btn btn-lgrey btn-sm btn-xs pull-left" ng-click="viewProgNote()"
id="dentalClaimProgressNoteBtn7777777777777">Prog. Notes</button>
<button id="cancelDentalClaimButton" type="button" class="btn btn-lgrey btn-sm btn-xs pull-right ml10"
ng-click="closeDntl();">Cancel</button>
<button id="DentalClaimBtn17" type="button" class="btn btn-blue btn-sm btn-xs pull-right ml10"
ng-click="saveData()">OK</button>
</div>
</div></div></div>
<script>
// Cancel and OK both hide the same backdrop the real closeDntl() /
// saveData() do — same reasoning hcfa_claim.html's script block uses.
document.getElementById('cancelDentalClaimButton').addEventListener('click', function () {
document.getElementById('dentalClaim7777777777777').style.display = 'none';
});
document.getElementById('DentalClaimBtn17').addEventListener('click', function () {
document.getElementById('dentalClaim7777777777777').style.display = 'none';
});
</script>
<script>
// ?footer=wrapped (review of unit C, 2026-10-05): wraps Cancel in a div
// whose id also starts with "dentalClaim", inside the modal. The form's
// window is found by walking up from the visible Cancel; an id-prefix-only
// window selector stopped at this wrapper, which holds neither the claim
// number nor the service lines. Runs before the load script so ?load=
// combines with it. The click handler stays on the moved button.
(function () {
if (!/[?&]footer=wrapped(&|$)/.test(location.search)) return;
var cancel = document.getElementById('cancelDentalClaimButton');
var wrap = document.createElement('div');
wrap.id = 'dentalClaimFooter7777777777777';
cancel.parentNode.insertBefore(wrap, cancel);
wrap.appendChild(cancel);
})();
</script>
<script>
// Angular's load, simulated (review item D7) — opt-in through the query
// string, so every test that loads this fixture plainly still sees a form
// that is already filled.
// ?load=delayed claim number and codes blank, filled 800 ms later
// ?load=never blank, and never filled (the timeout path)
// ?load=wrong filled 800 ms later with a DIFFERENT claim number
// ?load=noclaimno claim-number element removed; codes filled 800 ms later
// Codes are blanked as the .value PROPERTY only, which is where Angular
// keeps them: the value="" attribute still holds the template's code, so a
// reader that took the attribute would call the form loaded at once.
(function () {
var m = /[?&]load=(\w+)/.exec(location.search);
if (!m) return;
var mode = m[1];
var no = document.querySelector('[id^="dentalClaim"] [ng-bind="ClaimData.claimNo"]');
var codes = Array.prototype.slice.call(
document.querySelectorAll('[id^="dentalClaim"] [data-fieldname="web_cptcode"]'));
var want = codes.map(function (e) { return e.value; });
var claimNo = no ? no.textContent : '';
if (no) no.textContent = '';
if (mode === 'noclaimno' && no) { no.remove(); no = null; }
codes.forEach(function (e) { e.value = ''; });
if (mode === 'never') return;
setTimeout(function () {
if (no) no.textContent = (mode === 'wrong' ? '5000001' : claimNo);
codes.forEach(function (e, i) { e.value = want[i]; });
}, 800);
})();
</script>
</body>
</html>
+499
View File
@@ -0,0 +1,499 @@
<!doctype html>
<!--
A cut-down of the professional/HCFA "Claim" screen eCW served on 2026-09-17
for claim 9103000 (Commercial payer — United Health Care).
Reproduced on purpose, rather than saved from the live page: the real form
is patient data and must never be committed. This screen is NOT the UB
Claim form (no #UBClaimBtn17, no #BillType) — is_ub_claim_form() must
return False against this fixture, the same as it does against the real
claim.
The real DOM has none of the UB form's ids at all — no #UBClaimDiv,
#BillType, #icdCodesTable, #UBClaimTbl3/4/10/17, uBClaimPOS*/uBClaimMod1*.
Every id here carries the per-open timestamp 8888888888888 instead
(deliberately different from ub_claim.html's 9999999999999, so a selector
that had one baked in fails against the other).
What matters most, reproduced faithfully from the real DOM:
* there is only ONE tab covering ICD and CPT/HCPCS together
("ICD & CPT") — no separate CPT/HCPCS tab exists to click at all
* the CPT rows still carry the stable `CPTROW_0`/`CPTROW_1` ids, same as
the UB form
* but the per-field ids are entirely different (`billingClaimIpt4ngR0`,
not `uBClaimPOS0`) and are positional/sequential — NOT safe to match
by prefix the way the UB form's are. `data-fieldname` is what is
actually stable here (`ClaimCPTPOS`, `ClaimCPTMOD1`, ... and, the one
exception, `claimCPTCode` lower-case for the code cell) — that is
the real live-verified attribute this fixture exists to test against.
* the whole form sits inside angular-ui-bootstrap's own modal window —
`class="modal fade ng-isolate-scope claimModalBackdrop in"`,
`window-class="claimModalBackdrop"`, no id — which closes on Escape
WITHOUT running closeClaimScreen() (verified live, claims 9109000 and
9119000, 2026-09-29). The UB form's wrapper is `ubClaimModalBackdrop`
instead and the Dental screen has none.
* the payer is in TWO tables, neither timestamped: `#billingClaimTbl5`
under "ICD & CPT" (just P + Name, and its Name cell carries an edit
input as well as the name), and `#billingClaimTbl8` under
"Insurances & Payment" — the same columns as the UB form's
#UBClaimTbl3, plus Ins Id. Subscriber values here are made up.
-->
<html>
<body>
<div class="modal fade ng-isolate-scope claimModalBackdrop in" role="dialog" tabindex="-1"
modal-window window-class="claimModalBackdrop" ng-click="close($event)"
style="display:block; z-index:1050">
<div class="modal-dialog ui-draggable"><div class="modal-content">
<div id="div_Billingclaim8888888888888">
<div class="modal fade bluetheme billing-width right-panel-mode in" id="claimModal8888888888888" style="display:block">
<div class="modal-dialog visible" style="width: 1286px;">
<div class="modal-content" id="claimModalContent8888888888888">
<div class="modal-header">
<h4 class="modal-title">Claim
<span class="ml5 fs11 patient-identifier-span">VALENZUELA, Fabiola &nbsp; Oct 19, 1984 (41 yo F) &nbsp; Acc No. 550201</span>
</h4>
</div>
<div class="modal-body">
<table class="table"><tbody><tr>
<td><label>Claim No</label></td>
<td><span ng-bind="ClaimData.InvId" title="9103000">9103000</span></td>
</tr></tbody></table>
<ul id="billingClaimUl1" class="nav">
<li class="active"><a class="cursor" data-toggle="tab" data-target="#icd8888888888888">ICD &amp; CPT</a></li>
<li><a class="cursor" data-toggle="tab" data-target="#inp8888888888888">Insurances &amp; Payment</a></li>
<li><a class="cursor" data-toggle="tab" data-target="#addinf8888888888888">Additional Information</a></li>
</ul>
<div class="tab-content claim-tab">
<div class="tab-pane active" id="icd8888888888888">
<h4>ICD Codes (2)</h4>
<table id="icdCodesTable8888888888888" class="table table-bordered blue-fade-table">
<thead><tr><th>#</th><th></th><th>Code</th><th>Name</th><th></th></tr></thead>
<tbody ng-model="ICDCodes">
<tr ng-repeat="icd in ICDCodes">
<td class="text-center">1</td>
<td class="text-center"><input type="checkbox"></td>
<td title="Z30.430"><input id="billingClaimIpt2ngR0" data-fieldname="ClaimICDCode" type="text" value="Z30.430"></td>
<td title="Encounter for insertion of intrauterine contraceptive device">Encounter for insertion of intrauterine contraceptive device</td>
<td class="text-center"><button></button></td>
</tr>
<tr ng-repeat="icd in ICDCodes">
<td class="text-center">2</td>
<td class="text-center"><input type="checkbox"></td>
<td title="Z13.31"><input id="billingClaimIpt2ngR1" data-fieldname="ClaimICDCode" type="text" value="Z13.31"></td>
<td title="Negative depression screening">Negative depression screening</td>
<td class="text-center"><button></button></td>
</tr>
<tr id="3">
<td class="text-center">*</td>
<td></td>
<td><input type="text" id="txtnewIcd8888888888888" ng-model="newICD"></td>
<td></td><td></td>
</tr>
</tbody>
</table>
<h4>Insurances</h4>
<table id="billingClaimTbl5" class="table table-bordered blue-fade-table nomargin">
<thead><tr><th></th><th>Name</th></tr></thead>
<tbody>
<tr ng-repeat="insurance in Insurances track by $index">
<td><span ng-bind="insurance.sequanceNo">P</span></td>
<!-- eCW's own tag typo, <sapn>, reproduced as served -->
<td title="United Health Care"><input type="text" value="" style="display:none"><sapn ng-bind="insurance.InsName">United Health Care</sapn></td>
</tr>
</tbody>
</table>
<h4 class="blue-header">CPT/HCPCS (3)</h4>
<button id="claimAddCPTBtn8888888888888" type="button" class="btn btn-lgrey btn-xs" ng-click="addProcedureCode('');">Add</button>
<div class="allbrd cptTbl" id="cptTable8888888888888">
<table class="table table-bordered blue-fade-table" id="claimCPTCodesTable8888888888888">
<thead><tr>
<th class="text-center">#</th><th>&nbsp;</th><th>Code</th><th>POS</th><th>TOS</th>
<th>SDOS</th><th>EDOS</th><th>M1</th><th>M2</th><th>M3</th><th>M4</th>
<th>ICD1</th><th>ICD2</th><th>ICD3</th><th>ICD4</th><th>Units</th>
<th>Billed Fee</th><th>Pro Id</th>
</tr></thead>
<tbody>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_0">
<td class="text-center">1</td>
<td><input type="checkbox" ng-click="updateBillToIns($index)" ng-checked="cpt.BillToIns=='1'" checked></td>
<td title="Office Visit, Est Pt., Level 3"><input id="claimCPTCode0" data-fieldname="claimCPTCode" type="text" value="99213" readonly></td>
<td><input id="billingClaimIpt4ngR0" data-fieldname="ClaimCPTPOS" type="text" value="11"></td>
<td><input id="billingClaimIpt5ngR0" data-fieldname="ClaimCPTTOS" type="text" value="1"></td>
<td><input id="billingClaimIpt6ngR0" data-fieldname="ClaimCPTSDOS" type="text" value="07/07/2026"></td>
<td><input id="billingClaimIpt7ngR0" data-fieldname="ClaimCPTEDOS" type="text" value="07/07/2026"></td>
<td><input id="billingClaimIpt8ngR0" data-fieldname="ClaimCPTMOD1" type="text" value=""></td>
<td><input id="billingClaimIpt9ngR0" data-fieldname="ClaimCPTMOD2" type="text" value=""></td>
<td><input id="billingClaimIpt10ngR0" data-fieldname="ClaimCPTMOD3" type="text" value=""></td>
<td><input id="billingClaimIpt11ngR0" data-fieldname="ClaimCPTMOD4" type="text" value=""></td>
<td><input id="billingClaimIpt12ngR0" data-fieldname="ClaimCPTICD1" type="text" value="1"></td>
<td><input id="billingClaimIpt13ngR0" data-fieldname="ClaimCPTICD2" type="text" value="2"></td>
<td><input id="billingClaimIpt14ngR0" data-fieldname="ClaimCPTICD3" type="text" value="3"></td>
<td><input id="billingClaimIpt15ngR0" data-fieldname="ClaimCPTICD4" type="text" value=""></td>
<td><input id="billingClaimIpt16ngR0" data-fieldname="ClaimCPTUnits" type="text" value="1"></td>
<td title="210.00"><input id="billingClaimIpt17ngR0" data-fieldname="ClaimCPTBilledFee" type="text" value="210.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_1">
<td class="text-center">2</td>
<td><input type="checkbox" ng-click="updateBillToIns($index)" ng-checked="cpt.BillToIns=='1'" checked></td>
<td title="MIRENA/LNG-RELEASING IUC SYS 52MG 5 YR DUR"><input id="claimCPTCode1" data-fieldname="claimCPTCode" type="text" value="J7298" readonly></td>
<td><input id="billingClaimIpt4ngR1" data-fieldname="ClaimCPTPOS" type="text" value="11"></td>
<td><input id="billingClaimIpt5ngR1" data-fieldname="ClaimCPTTOS" type="text" value="1"></td>
<td><input id="billingClaimIpt6ngR1" data-fieldname="ClaimCPTSDOS" type="text" value="07/07/2026"></td>
<td><input id="billingClaimIpt7ngR1" data-fieldname="ClaimCPTEDOS" type="text" value="07/07/2026"></td>
<td><input id="billingClaimIpt8ngR1" data-fieldname="ClaimCPTMOD1" type="text" value=""></td>
<td><input id="billingClaimIpt9ngR1" data-fieldname="ClaimCPTMOD2" type="text" value=""></td>
<td><input id="billingClaimIpt10ngR1" data-fieldname="ClaimCPTMOD3" type="text" value=""></td>
<td><input id="billingClaimIpt11ngR1" data-fieldname="ClaimCPTMOD4" type="text" value=""></td>
<td><input id="billingClaimIpt12ngR1" data-fieldname="ClaimCPTICD1" type="text" value="1"></td>
<td><input id="billingClaimIpt13ngR1" data-fieldname="ClaimCPTICD2" type="text" value=""></td>
<td><input id="billingClaimIpt14ngR1" data-fieldname="ClaimCPTICD3" type="text" value=""></td>
<td><input id="billingClaimIpt15ngR1" data-fieldname="ClaimCPTICD4" type="text" value=""></td>
<td><input id="billingClaimIpt16ngR1" data-fieldname="ClaimCPTUnits" type="text" value="1"></td>
<td title="1200.00"><input id="billingClaimIpt17ngR1" data-fieldname="ClaimCPTBilledFee" type="text" value="1200.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_2">
<td class="text-center">3</td>
<!-- Unchecked on purpose: the real bug report - G8510 had
been excluded from billing and needs re-including once
its ICD pointer is corrected. -->
<td><input type="checkbox" ng-click="updateBillToIns($index)" ng-checked="cpt.BillToIns=='1'"></td>
<td title="NEG SCR D PT NOT ELIG F/U/PLN DOC"><input id="claimCPTCode2" data-fieldname="claimCPTCode" type="text" value="G8510" readonly></td>
<td><input id="billingClaimIpt4ngR2" data-fieldname="ClaimCPTPOS" type="text" value="11"></td>
<td><input id="billingClaimIpt5ngR2" data-fieldname="ClaimCPTTOS" type="text" value="1"></td>
<td><input id="billingClaimIpt6ngR2" data-fieldname="ClaimCPTSDOS" type="text" value="07/07/2026"></td>
<td><input id="billingClaimIpt7ngR2" data-fieldname="ClaimCPTEDOS" type="text" value="07/07/2026"></td>
<td><input id="billingClaimIpt8ngR2" data-fieldname="ClaimCPTMOD1" type="text" value=""></td>
<td><input id="billingClaimIpt9ngR2" data-fieldname="ClaimCPTMOD2" type="text" value=""></td>
<td><input id="billingClaimIpt10ngR2" data-fieldname="ClaimCPTMOD3" type="text" value=""></td>
<td><input id="billingClaimIpt11ngR2" data-fieldname="ClaimCPTMOD4" type="text" value=""></td>
<!-- Wrong on purpose: points at ICD1 (Z30.430), not the
depression pointer (2) - this is the "target code
needs retagging" case set_cpt_pos_modifier's sibling
must fix. -->
<td><input id="billingClaimIpt12ngR2" data-fieldname="ClaimCPTICD1" type="text" value="1"></td>
<td><input id="billingClaimIpt13ngR2" data-fieldname="ClaimCPTICD2" type="text" value=""></td>
<td><input id="billingClaimIpt14ngR2" data-fieldname="ClaimCPTICD3" type="text" value=""></td>
<td><input id="billingClaimIpt15ngR2" data-fieldname="ClaimCPTICD4" type="text" value=""></td>
<td><input id="billingClaimIpt16ngR2" data-fieldname="ClaimCPTUnits" type="text" value="1"></td>
<td title="65.00"><input id="billingClaimIpt17ngR2" data-fieldname="ClaimCPTBilledFee" type="text" value="65.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<!-- the blank entry row eCW leaves at the bottom: no CPTROW_ id -->
<tr>
<td class="text-center">*</td>
<td class="text-center"><input type="checkbox" checked></td>
<td><input type="text" ng-model="newCPT"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="tab-pane" id="inp8888888888888">
<h4>Insurances</h4>
<table id="billingClaimTbl8" class="table table-bordered blue-fade-table nomargin">
<thead><tr>
<th></th><th>Bill To</th><th>Ins Id</th><th>Name</th><th>State</th>
<th>Subscriber No</th><th>Rel</th><th>Insured</th><th>Group No</th>
</tr></thead>
<tbody>
<tr ng-repeat="insurance in Insurances track by $index">
<td><span ng-bind="insurance.sequanceNo">P</span></td>
<td><input type="checkbox" ng-model="insurance.PrimIns" checked></td>
<td><span ng-bind="insurance.InsId">1660</span></td>
<td><span ng-bind="insurance.InsName">United Health Care</span></td>
<td><span ng-bind="insurance.InsState">CO</span></td>
<td><span ng-bind="insurance.SubscriberNo">X00000000</span></td>
<td><span ng-bind="insurance.SubscriberRel">1</span></td>
<td><span ng-bind="insurance.SubscriberName">Doe, Alex</span></td>
<td><input type="text" value="" style="display:none"><span ng-bind="insurance.GroupNo"></span></td>
</tr>
</tbody>
</table>
</div>
</div>
</div><!-- /modal-body -->
<!--
eCW's Fee Schedule / CPT picker (opened by the "Add" button above),
reproduced from the real DOM captured on a live "Claim" screen (claim
9109000). Unlike everything else on the claim screen, ITS OWN controls
carry stable ids with no per-open timestamp at all — this is a shared,
reusable component, not something scoped to one claim's open session.
-->
<div class="modal fade bluetheme" id="claimFeeScheduleModal" style="display:none">
<div class="modal-dialog"><div class="modal-content">
<div class="modal-header">
<button id="claimFeeScheduleBtn1" type="button" class="close">&times;</button>
<h4 class="modal-title">Fee Schedule</h4>
</div>
<div class="modal-body">
<table class="table table-bordered claimFSCPTTbl" id="example1">
<thead><tr><th>Id</th><th>CPT</th><th>Name</th><th>Fee</th></tr></thead>
<tbody id="claimFSCPTTblBody"></tbody>
</table>
</div>
<div class="modal-footer">
<input id="claimFeeScheduleIpt6" type="text" placeholder="Search CPT">
<button id="claimFeeScheduleBtn8" type="button">Cancel</button>
<button id="claimFeeSchOkBtn" type="button">OK</button>
</div>
</div></div>
</div>
<div class="grey-bg modal-footer">
<button id="claimProgressNoteBtn8888888888888" type="button" class="btn btn-lgrey btn-sm btn-xs pull-left"
ng-click="viewProgNote()">Prog. Notes</button>
<button id="billingClaimBtn36" type="button" class="btn btn-lgrey btn-sm btn-xs pull-right"
ng-click="closeClaimScreen()">Cancel</button>
<button id="claimScreenOkBtn8888888888888" type="button" class="btn btn-blue btn-sm btn-xs pull-right"
ng-click="currentButtonAction='';saveAllData()">OK</button>
</div>
</div></div></div>
</div></div></div></div><!-- /div_Billingclaim, modal-content, modal-dialog, uib window -->
<script>
// Cancel and OK both hide the same backdrop the real closeClaimScreen() /
// saveAllData() do — added so tests can prove the modal actually closes on
// both paths, exactly the same reasoning ub_claim.html's script block uses.
//
// Both take the whole uib window out of the DOM, as eCW does: after a
// real close, not one #billingClaimTbl8 was left in the document.
// `closeClaimScreenRan` is what lets a test tell a real Cancel apart from
// the form vanishing under an Escape.
window.closeClaimScreenRan = false;
function removeClaimWindow() {
var w = document.querySelector('.claimModalBackdrop');
if (w) w.remove();
}
document.getElementById('billingClaimBtn36').addEventListener('click', function () {
window.closeClaimScreenRan = true;
removeClaimWindow();
});
document.getElementById('claimScreenOkBtn8888888888888').addEventListener('click', function () {
removeClaimWindow();
});
// uib's modal stack dismisses its topmost window on Escape — for this
// form that means gone, closeClaimScreen() never run (verified live,
// claim 9109000). The Fee Schedule picker is on top while it is showing,
// so Escape goes to it instead.
document.addEventListener('keydown', function (e) {
if (e.key !== 'Escape') return;
var picker = document.getElementById('claimFeeScheduleModal');
if (picker && picker.style.display === 'block') return;
removeClaimWindow();
});
// The real DOM (claim 9103000) carries ng-blur="updateCPTMod(...)" on every
// M1 input, same as the UB form — reproduced as a data attribute so a test
// can prove set_cpt_pos_modifier() blurs the field on THIS screen too.
document.querySelectorAll('[data-fieldname="ClaimCPTMOD1"]').forEach(function (el) {
el.addEventListener('blur', function () { el.dataset.blurred = '1'; });
});
// The Fee Schedule picker: a small seed catalog, filtered by the search
// box the same "Starts With" way the real picker defaults to. This
// fakes eCW's own lookup/filter logic, not the fact that add_cpt_row()
// clicks Add, types a search, selects the one match, and clicks OK —
// that sequence is what the test proves, against real, stable ids.
var feeScheduleCatalog = [
{id: '509263', code: 'G2025', name: 'Telehealth originating site facility fee', fee: '25.00'},
{id: '488892', code: 'G2026', name: 'Unrelated decoy code', fee: '0.00'},
];
var feeScheduleSelectedCode = null;
function renderFeeScheduleResults(filterText) {
var tbody = document.getElementById('claimFSCPTTblBody');
tbody.innerHTML = '';
var q = (filterText || '').toUpperCase();
feeScheduleCatalog
.filter(function (row) { return row.code.toUpperCase().indexOf(q) === 0; })
.forEach(function (row) {
var tr = document.createElement('tr');
tr.innerHTML =
'<td>' + row.id + '</td>'
+ '<td><span>' + row.code + '</span></td>'
+ '<td>' + row.name + '</td>'
+ '<td>' + row.fee + '</td>';
tr.addEventListener('click', function () { feeScheduleSelectedCode = row.code; });
tbody.appendChild(tr);
});
}
document.getElementById('claimAddCPTBtn8888888888888').addEventListener('click', function () {
feeScheduleSelectedCode = null;
document.getElementById('claimFeeScheduleIpt6').value = '';
renderFeeScheduleResults('');
document.getElementById('claimFeeScheduleModal').style.display = 'block';
});
document.getElementById('claimFeeScheduleIpt6').addEventListener('input', function () {
renderFeeScheduleResults(this.value);
});
document.getElementById('claimFeeScheduleBtn8').addEventListener('click', function () {
document.getElementById('claimFeeScheduleModal').style.display = 'none';
});
document.getElementById('claimFeeSchOkBtn').addEventListener('click', function () {
document.getElementById('claimFeeScheduleModal').style.display = 'none';
if (!feeScheduleSelectedCode) return;
var tbody = document.querySelector('#claimCPTCodesTable8888888888888 tbody');
var addRowTr = tbody.querySelector('tr:last-child');
var n = document.querySelectorAll('#claimCPTCodesTable8888888888888 [id^="CPTROW_"]').length;
var newRow = document.createElement('tr');
newRow.id = 'CPTROW_' + n;
newRow.innerHTML =
'<td class="text-center">' + (n + 1) + '</td>'
+ '<td><input type="checkbox" ng-click="updateBillToIns(' + n + ')" checked></td>'
+ '<td><input data-fieldname="claimCPTCode" type="text" value="' + feeScheduleSelectedCode + '" readonly></td>'
+ '<td><input data-fieldname="ClaimCPTPOS" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTTOS" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTSDOS" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTEDOS" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTMOD1" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTMOD2" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTMOD3" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTMOD4" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTICD1" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTICD2" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTICD3" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTICD4" type="text" value=""></td>'
+ '<td><input data-fieldname="ClaimCPTUnits" type="text" value="1"></td>'
+ '<td><input data-fieldname="ClaimCPTBilledFee" type="text" value="25.00"></td>'
+ '<td><input type="text" value="" readonly></td>';
tbody.insertBefore(newRow, addRowTr);
newRow.querySelector('[data-fieldname="ClaimCPTMOD1"]')
.addEventListener('blur', function () { this.dataset.blurred = '1'; });
});
document.getElementById('claimProgressNoteBtn8888888888888').addEventListener('click', function () {
var m = document.createElement('div');
m.className = 'modal in';
m.id = 'progressNoteViewerDiv8888888888888';
m.style.display = 'block';
m.innerHTML =
'<div class="modal-dialog"><div class="modal-content">'
+ '<div class="modal-header"><h4 class="modal-title">Progress Note</h4></div>'
+ '<div class="modal-body">'
+ '<iframe id="progressNoteFrame" src="progress_note.html" '
+ 'style="width:900px;height:400px;border:0"></iframe>'
+ '</div>'
+ '<div class="modal-footer">'
+ '<button type="button" class="btn btn-blue btn-sm btn-xs pull-right" '
+ 'ng-click="closeProgressNoteViwer()">Close</button>'
+ '</div>'
+ '</div></div>';
document.body.appendChild(m);
m.querySelector('[ng-click="closeProgressNoteViwer()"]')
.addEventListener('click', function () { m.style.display = 'none'; });
});
</script>
<script>
// Angular's load, simulated (review item D7) — opt-in through the query
// string, so every test that loads this fixture plainly still sees a form
// that is already filled.
// ?load=delayed claim number and codes blank, filled 800 ms later
// ?load=never blank, and never filled (the timeout path)
// ?load=wrong filled 800 ms later with a DIFFERENT claim number
// ?load=noclaimno claim-number element removed; codes filled 800 ms later
// ?load=staggered claim number and row 1 at 800 ms, row 2 at 1100 ms,
// row 3 at 1400 ms — Angular filling one digest at a
// time, so the first non-zero count is not the last
// Plus, combinable with any ?load= mode:
// &stale=other a HIDDEN copy of an earlier claim's form (claim
// 5000002, one filled CPT row) sits in the DOM ahead of
// this one, and this form's claim number stays hidden
// until it is filled — eCW leaves closed forms behind
// &stale=same the same hidden leftover, but showing THIS claim's
// number, so only its filled row could fool a reader
// Codes are blanked as the .value PROPERTY only, which is where Angular
// keeps them: the value="" attribute still holds the template's code, so a
// reader that took the attribute would call the form loaded at once.
//
// And the Prog. Notes button's ng-disabled="!FormData.EnableProgressNote",
// which Angular flips only once the claim has loaded:
// ?pn=late disabled, enabled 1 s later
// ?pn=off disabled for good
(function () {
var m = /[?&]pn=(\w+)/.exec(location.search);
if (!m) return;
var b = document.querySelector('[ng-click="viewProgNote()"]');
b.disabled = true;
if (m[1] === 'late') setTimeout(function () { b.disabled = false; }, 1000);
})();
(function () {
var m = /[?&]load=(\w+)/.exec(location.search);
if (!m) return;
var mode = m[1];
var no = document.querySelector('[ng-bind="ClaimData.InvId"]');
var codes = Array.prototype.slice.call(
document.querySelectorAll('tr[id^="CPTROW_"] [data-fieldname="claimCPTCode"]'));
var want = codes.map(function (e) { return e.value; });
var claimNo = no ? no.textContent : '';
var s = /[?&]stale=(\w+)/.exec(location.search);
if (s) {
// Built before this form's values are blanked, and first in <body>.
var old = document.createElement('div');
old.className = 'modal fade ng-isolate-scope claimModalBackdrop';
old.style.display = 'none';
old.innerHTML =
'<span ng-bind="ClaimData.InvId">'
+ (s[1] === 'same' ? claimNo : '5000002') + '</span>'
+ '<table><tbody><tr id="CPTROW_0"><td>'
+ '<input data-fieldname="claimCPTCode" type="text" value="99999">'
+ '</td></tr></tbody></table>'
+ '<button type="button" ng-click="closeClaimScreen()">Cancel</button>';
document.body.insertBefore(old, document.body.firstChild);
if (no) no.style.display = 'none';
}
if (no) no.textContent = '';
if (mode === 'noclaimno' && no) { no.remove(); no = null; }
codes.forEach(function (e) { e.value = ''; });
if (mode === 'never') return;
if (mode === 'staggered') {
codes.forEach(function (e, i) {
setTimeout(function () {
if (i === 0 && no) { no.textContent = claimNo; no.style.display = ''; }
e.value = want[i];
}, 800 + 300 * i);
});
return;
}
setTimeout(function () {
if (no) {
no.textContent = (mode === 'wrong' ? '5000001' : claimNo);
no.style.display = '';
}
codes.forEach(function (e, i) { e.value = want[i]; });
}, 800);
})();
</script>
</body>
</html>
+331
View File
@@ -0,0 +1,331 @@
<html>
<!--
A cut-down of the Progress Note eCW served on 2026-09-07 for claim 9104000.
Reproduced rather than saved: the real note is dense patient narrative and
must never be committed. Trimmed to the structures the extractor reaches for,
with the real attribute names kept exactly:
* prisma-section="..." on every section row - eCW's own labels, and the
whole reason this note is read as structure instead of as prose
* "Footer" repeats four times, so a naive dict build would drop the
signature block. The extractor joins repeats; a test covers it.
* #chartLockedId is display:none - innerText returns "" for it, so it has
to be read with textContent
* the Assessments number sits in its own <td>, away from the text
* the Procedure Code line carries the modifier inline: "... Modifiers: GT"
-->
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<style type="text/css">
.PtHeading { font-size: 18pt; font-weight: bold; }
.PtData { font-size: 9pt; font-weight: bold; }
.leftPaneHeading, .rightPaneHeading { font-size: 10pt; }
.leftPaneData, .rightPaneData { font-size: 9pt; }
.PNSig { font-size: 10pt; font-weight: bold; }
.TableFooter { font-size: 9pt; font-weight: bold; }
</style>
</head>
<body class="mousetrap">
<hr>
<table cellpadding="0" cellspacing="0" border="0" width="99%">
<thead id="mainThead">
<tr class="patient_header_tr">
<td><span>SAMPLE, Pat Q <b>DOB:</b> 05/11/1979 (47 yo F)
<b>Acc No.</b> 900123 <b>DOS:</b> 06/29/2026</span></td>
</tr>
</thead>
<tbody>
<tr><td>
<table cellspacing="0" cellpadding="0" width="100%" prisma-section="Header">
<tbody>
<tr class="PtHeading"><td align="right"><b>Sample, Pat Q</b></td></tr>
<tr class="PtData"><td align="right">47 Y&nbsp; old &nbsp;Female,&nbsp;DOB: 05/11/1979</td></tr>
<tr class="PtData"><td align="right">Account Number:&nbsp;900123</td></tr>
<tr class="PtData"><td align="right">100 SAMPLE ST, ANYTOWN, CO-80000-0000</td></tr>
<tr class="PtData"><td align="right">Home: 555-010-0100</td></tr>
<tr class="PtData"><td align="right">Guarantor:&nbsp;Sample, Pat Q
Insurance:&nbsp;BH COLORADO ACCESS Payer ID:&nbsp;UOACC</td></tr>
<tr class="PtData"><td align="right">PCP:&nbsp;Jordan K Rivera</td></tr>
<tr class="PtData"><td align="right">Appointment Facility:&nbsp;Brighton Womens Clinic</td></tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr>
<!-- the left pane -->
<td width="35%" valign="top" class="lefttbl" id="leftPanelModernStyle">
<table cellspacing="8" cellpadding="0" border="0" width="100%">
<tbody>
<!-- present but empty on this note, exactly as served -->
<tr prisma-section="Active Problem List"><td valign="top"></td></tr>
<tr prisma-section="Past Medical History">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="leftPaneHeading"><td>Past Medical History</td></tr>
<tr class="leftPaneData"><td>
<ul style="padding-left: 25px;margin-bottom: 0px;">
<li>Current Tobacco Use- about 1 pack per day, started at age 14.</li>
<li>Generalized Anxiety Disorder.</li>
<li>Low Back Pain with Right-Sided Sciatica.</li>
</ul>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Surgical History">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="leftPaneHeading"><td><b>Surgical History</b></td></tr>
<tr class="leftPaneData"><td>
<ul style="padding-left: 25px;margin-bottom: 0px;">
<li>Cyst Removal Right Breast - fibrous tissue&nbsp;1997</li>
</ul>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Family History">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="leftPaneHeading"><td><b>Family History</b></td></tr>
<tr class="leftPaneData"><td>
<ul style="padding-left: 25px;margin-bottom: 0px;">
<li>Mother: alive 66 yrs, diagnosed with Cancer</li>
<li>Father: alive 76 yrs, diagnosed with Hypertension</li>
<li>Siblings: alive, diagnosed with Hypertension</li>
</ul>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Social History">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="leftPaneHeading"><td><b>Social History</b></td></tr>
<tr class="leftPaneData"><td>
<table class="leftPaneData" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr><td>Tobacco use</td></tr>
<tr><td>Tobacco Status:&nbsp;<i>Current tobacco user pack a day</i></td></tr>
<tr><td>Depression Screening PHQ-2</td></tr>
<tr><td>Screening Test Result&nbsp;<i>Positive - 3 or more</i></td></tr>
<tr><td>Follow Up Plan (required)&nbsp;<i>Schedule f/u with Behavioral Health</i></td></tr>
</tbody>
</table>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Hospitalization/Major Diagnostic Procedure">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="leftPaneHeading"><td><b>Hospitalization/Major Diagnostic Procedure</b></td></tr>
<tr class="leftPaneData"><td>
<ul style="padding-left: 25px;margin-bottom: 0px;">
<li>Childbirth x 1 vaginal, uncomplicated</li>
</ul>
</td></tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td>
<!-- the right pane -->
<td width="65%" valign="top">
<table id="rightPanelDataTable" cellspacing="8" cellpadding="0" border="0" width="100%">
<tbody>
<tr prisma-section="Reason for Appointment">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="rightPaneHeading"><td><b>Reason for Appointment</b></td></tr>
<tr class="rightPaneData"><td>
<table class="rightPaneData" cellspacing="0" cellpadding="0" width="100%">
<tbody><tr>
<td width="28px">&nbsp;&nbsp;1.&nbsp;</td>
<td>BH Outreach</td>
</tr></tbody>
</table>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="History of Present Illness">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="rightPaneHeading"><td><b>History of Present Illness</b></td></tr>
<tr class="rightPaneData"><td>
<table class="rightPaneData" cellspacing="0" cellpadding="0" width="100%">
<tbody><tr><td>&nbsp;&nbsp;&nbsp;<u>TELEHEALTH</u>:&nbsp;</td></tr></tbody>
</table>
<table width="100%" class="rightPaneData" cellspacing="0" cellpadding="0">
<tbody><tr>
<td width="28px"></td>
<td><b>BH Visit Details</b><br>
BHP conducted a scheduled outreach telephone call as part of
ongoing behavioral health outreach services.<br>
<b>Assessment</b><br>
<b>Columbia Suicide Severity Rating Scale (C-SSRS):</b> Low Risk.<br>
<b>Outcome Rating Scale (ORS):</b> Score of 4; Clinical.<br>
<b>Plan</b><br>
No behavioral health follow-up appointment was scheduled at this time.
</td>
</tr></tbody>
</table>
<table class="rightPaneData" cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr><td>Session Start:&nbsp;<i>1:00pm.</i></td></tr>
<tr><td>Session End:&nbsp;<i>2:00pm.</i></td></tr>
<tr><td>Session Duration (Minutes):&nbsp;<i>60Minutes.</i></td></tr>
<tr><td>Session Setting (PoS)&nbsp;<i>Telehealth</i></td></tr>
<tr><td>Mode of Treatment:&nbsp;<i>Telephone</i></td></tr>
</tbody>
</table>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Assessments">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="rightPaneHeading"><td><b>Assessments</b></td></tr>
</tbody>
</table>
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="rightPaneData">
<td width="28px" style="text-align: right; padding-right: 3px;">1.</td>
<td>Illness, unspecified - R69 (Primary)&nbsp;&nbsp;&nbsp;</td>
</tr>
<tr class="rightPaneData">
<td width="28px" style="text-align: right; padding-right: 3px;">2.</td>
<td>Generalized anxiety disorder - F41.1&nbsp;&nbsp;&nbsp;</td>
</tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Labs">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="rightPaneHeading"><td><b>Labs&nbsp;</b></td></tr>
<tr class="rightPaneData">
<td><u>Lab: BH - Outcome Rating Scale (ORS)
(Collection Date &amp; Time - 06/29/2026)</u></td>
</tr>
<tr><td>
<table border="0" class="rightPaneData" width="100%">
<tbody>
<tr><td width="50%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Individually</td>
<td width="10%">1</td><td width="10%"></td><td width="30%"></td></tr>
<tr><td width="50%">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Total</td>
<td width="10%">4</td><td width="10%"></td><td width="30%"></td></tr>
</tbody>
</table>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Procedure Codes">
<td valign="top">
<table cellspacing="0" cellpadding="0" width="100%">
<tbody>
<tr class="rightPaneHeading"><td><b>Procedure Codes</b></td></tr>
<tr class="rightPaneData"><td>
<ul style="padding-left: 28px;margin-bottom: 0px;">
<li>H0023 Behavioral Health Outreach Service (TH). Modifiers: GT</li>
<li>90791 Psychiatric diagnostic evaluation.</li>
</ul>
</td></tr>
</tbody>
</table>
</td>
</tr>
<tr prisma-section="Care Plan Details">
<td valign="top">
<div class="leftPaneHeading">Care Plan Details</div>
<table style="width:99%; border-collapse: collapse;" cellspacing="0" cellpadding="1">
<tbody><tr></tr></tbody>
</table>
</td>
</tr>
<!-- "Footer" repeats: the signature, the status, and the facility
block are three separate prisma-section="Footer" rows. -->
<tr prisma-section="Footer">
<td valign="top"><img id="signature1" width="175px" height="100px" src=""></td>
</tr>
<tr class="PNSig" prisma-section="Footer">
<td valign="top">Electronically signed by Provider: Morgan Lee Taylor , LPC
on 07/13/2026 at 07:52 PM MDT</td>
</tr>
<tr class="PNSig" prisma-section="Footer">
<td valign="top">Sign off status: Completed</td>
</tr>
<tr class="Facility" prisma-section="Footer">
<td align="center">
<hr><br>Brighton Womens Clinic<br>30 S 20TH AVE<br>
BRIGHTON, CO 80601-3705<br>Tel:&nbsp;303-655-6180<br>
Fax:&nbsp;720-685-8714<br>
</td>
</tr>
</tbody>
</table>
</td>
</tr>
</tbody>
</table>
</td></tr>
</tbody>
<tfoot class="mainTfoot" style="display:table-footer-group">
<tr prisma-section="Footer">
<td>
<table cellspacing="0" cellpadding="0" border="0" width="100%">
<tbody>
<tr class="TableFooter"><td align="center">
Progress Note:&nbsp;Morgan Lee Taylor&nbsp;&nbsp;&nbsp;&nbsp;06/29/2026</td></tr>
<tr class="eclinicalworks"><td align="center">
Note generated by eClinicalWorks EMR/PM Software</td></tr>
</tbody>
</table>
</td>
</tr>
</tfoot>
</table>
<span name="chartLockedId" id="chartLockedId" style="display:none; color:white">true</span>
</body>
</html>
+162
View File
@@ -0,0 +1,162 @@
<!doctype html>
<!--
A claim screen's Prog. Notes button whose note arrives LATE — the shape of
the 3 misses in ~115 note reads behind review item D8 (2026-10-01): the
viewer had opened, but the note document inside it had not loaded yet, so
a fixed 3 s sleep and one probe reported "nothing" and the claim went out
Clean with telehealth never checked.
Same split as progress_note_host.html: the note is a whole document in an
IFRAME inside the viewer modal, and Close (eCW's own "Viwer" typo) lives on
the parent page. The note itself is progress_note.html, made-up data.
The mode is chosen by query string:
?mode=slow&delay=3500 viewer opens at once on an empty frame; the note
document is loaded into it `delay` ms later
(3.5 s by default — longer than the old 3 s sleep)
?mode=never viewer opens on a frame that never gets a note
?mode=reclick the first click does nothing at all; the second
opens the viewer with the note
?mode=growing the note keeps gaining sections every 200 ms and
never settles
?mode=empty the note's header (#mainThead) arrives and nothing
under it ever does: a note marker, 0 sections
?mode=stalled&delay=1500
the note document is streamed: its header and two
sections are parsed, then the "server" stalls for
`delay` ms (readyState stays "loading") before the
Procedure Codes and the end of the document arrive
?mode=reused&delay=1500
a viewer from an EARLIER claim is already in the
DOM, hidden (Close only hides it), its iframe still
holding that claim's note (procedure A1111). The
click shows that same viewer again and its iframe
gets this claim's note (H0023) `delay` ms later
?mode=tab&delay=2000 the click opens a new tab at once on about:blank;
the note is loaded into it `delay` ms later (past
the halfway point of a 3 s wait) and there is no
in-page viewer at all
-->
<html>
<head><title>Prog. Notes, delayed</title></head>
<body>
<button type="button" ng-click="viewProgNote()">Prog. Notes</button>
<script>
var params = new URLSearchParams(location.search);
var mode = params.get('mode') || 'slow';
var delay = parseInt(params.get('delay') || '3500', 10);
window.progNoteClicks = 0;
function openViewer() {
var m = document.createElement('div');
m.className = 'modal in';
m.id = 'progressNoteViewerDiv6666666666666';
m.style.display = 'block';
m.innerHTML =
'<div class="modal-dialog"><div class="modal-content">'
+ '<div class="modal-body">'
+ '<iframe id="progressNoteFrame" src="about:blank" '
+ 'style="width:900px;height:400px;border:0"></iframe>'
+ '</div>'
+ '<div class="modal-footer">'
+ '<button type="button" ng-click="closeProgressNoteViwer()">Close</button>'
+ '</div>'
+ '</div></div>';
document.body.appendChild(m);
m.querySelector('[ng-click="closeProgressNoteViwer()"]')
.addEventListener('click', function () { m.remove(); });
return m.querySelector('iframe');
}
// A note that never stops growing: a header (the note marker) and one more
// prisma-section every 200 ms.
var GROWING =
'<html><body><table><thead id="mainThead"><tr><td>Header</td></tr></thead>'
+ '<tbody id="b"></tbody></table><script>'
+ 'var n = 0; setInterval(function () {'
+ ' var tr = document.createElement("tr");'
+ ' tr.setAttribute("prisma-section", "Section " + (++n));'
+ ' tr.innerHTML = "<td>line " + n + "</td>";'
+ ' document.getElementById("b").appendChild(tr);'
+ '}, 200);</' + 'script></body></html>';
// The header alone: the note marker is there, not one section ever is.
var EMPTY =
'<html><body><table><thead id="mainThead"><tr><td>Header</td></tr>'
+ '</thead><tbody></tbody></table></body></html>';
// A small whole note with one procedure code — made-up data.
function noteDoc(code) {
return '<html><body><table><thead id="mainThead"><tr><td>Header</td>'
+ '</tr></thead><tbody>'
+ '<tr prisma-section="Assessments"><td>1. Illness - R69</td></tr>'
+ '<tr prisma-section="Procedure Codes"><td><ul><li>' + code
+ ' Made-up procedure. Modifiers: GT</li></ul></td></tr>'
+ '</tbody></table></body></html>';
}
// 'reused': the earlier claim's viewer, hidden by its Close, still in the
// DOM with that claim's note in its iframe.
var leftover = null;
if (mode === 'reused') {
leftover = openViewer();
leftover.srcdoc = noteDoc('A1111');
var lm = leftover.closest('.modal');
lm.style.display = 'none';
var lc = lm.querySelector('[ng-click="closeProgressNoteViwer()"]');
var hide = lc.cloneNode(true); // drop openViewer's remove() handler
lc.replaceWith(hide);
hide.addEventListener('click', function () { lm.style.display = 'none'; });
}
document.querySelector('[ng-click="viewProgNote()"]')
.addEventListener('click', function () {
window.progNoteClicks++;
if (mode === 'reclick' && window.progNoteClicks === 1) return;
if (mode === 'reused') {
leftover.closest('.modal').style.display = 'block';
setTimeout(function () { leftover.srcdoc = noteDoc('H0023'); }, delay);
return;
}
if (mode === 'tab') {
var w = window.open('about:blank', '_blank');
setTimeout(function () {
w.location.href = new URL('progress_note.html', location.href).href;
}, delay);
return;
}
var frame = openViewer();
if (mode === 'stalled') {
// document.open() without close(): readyState stays "loading"
// until the rest of the document is written — a streamed response.
var d = frame.contentDocument;
d.open();
d.write('<html><body><table><thead id="mainThead"><tr><td>Header'
+ '</td></tr></thead><tbody>'
+ '<tr prisma-section="History of Present Illness"><td>hpi</td></tr>'
+ '<tr prisma-section="Assessments"><td>1. Illness - R69</td></tr>');
setTimeout(function () {
d.write('<tr prisma-section="Procedure Codes"><td><ul><li>H0023 '
+ 'Behavioral Health Outreach Service (TH). Modifiers: GT</li>'
+ '</ul></td></tr></tbody></table></body></html>');
d.close();
}, delay);
return;
}
if (mode === 'slow') {
setTimeout(function () { frame.src = 'progress_note.html'; }, delay);
} else if (mode === 'reclick') {
frame.src = 'progress_note.html';
} else if (mode === 'growing') {
frame.srcdoc = GROWING;
} else if (mode === 'empty') {
frame.srcdoc = EMPTY;
}
// 'never': the frame stays about:blank.
});
</script>
</body>
</html>
+50
View File
@@ -0,0 +1,50 @@
<!doctype html>
<!--
The Progress Note viewer as it actually arrives: the note is a whole printable
document with its own <html>, so eCW hosts it in an IFRAME inside a modal, and
the Close button lives on the PARENT page - not in the note.
That split is the trap this fixture exists for. Reading the modal's innerText
finds nothing, because iframe content is not part of it; and looking for Close
inside the note document finds nothing either. progress_note.find() has to
walk the frames, and progress_note.close() has to click on the parent.
The Close button's ng-click is spelled "closeProgressNoteViwer" - eCW's own
typo, reproduced exactly, because correcting it would match nothing.
-->
<html>
<head><title>Progress Note Viewer</title></head>
<body>
<div class="modal in" id="progressNoteViewerDiv1788790287089" style="display:block">
<div class="modal-dialog" style="width:1200px">
<div class="modal-content">
<div class="modal-header">
<h4 class="modal-title">Progress Note</h4>
</div>
<div class="modal-body" style="height:600px">
<iframe id="progressNoteFrame" src="progress_note.html"
style="width:100%;height:560px;border:0"></iframe>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-blue btn-sm btn-xs pull-right"
ng-click="closeProgressNoteViwer()">Close</button>
</div>
</div>
</div>
</div>
<script>
document.querySelector('[ng-click="closeProgressNoteViwer()"]')
.addEventListener('click', function () {
document.getElementById('progressNoteViewerDiv1788790287089')
.style.display = 'none';
});
</script>
</body>
</html>
+93
View File
@@ -0,0 +1,93 @@
<!doctype html>
<html>
<head><meta charset="utf-8"><title>sliding fee fixture</title>
<style>.hide { display: none; }</style></head>
<body>
<!--
Minimal copy of the eCW path, attribute-for-attribute where the bot
matches on it (Dom.txt, UB claim 9124000): the claim header "Info"
button, Patient Information (#ptInfo) with its Sliding Fee Schedule
button and Save/Cancel, the unsaved-data prompt, and the Sliding Fee
Schedule modal whose inputs Angular fills a moment after it shows.
Fictional values only.
Knobs, set from the test before clicking:
window.fixture.disabled Sliding Fee Schedule button disabled
window.fixture.values what the modal fills in (null = stays blank)
window.fixture.prompt Cancel raises the "unsaved data" prompt
Evidence the test reads back:
window.saved any Save was clicked (must stay false)
-->
<div id="UBClaimDiv">
<button type="button" id="claimPatientInfo1790766147287"
ng-click="loadPatientHubnInfo('Info');">Info</button>
</div>
<div class="modal hide" id="ptInfo">
<div class="modal-content" id="ptInfoModal">
<button id="savePrompt-tplBtn1" type="button" class="close"
ng-click="closeModalWindow()">x</button>
<div id="savePrompt" class="hide">
You have unsaved data. Click Save to retain your changes.
<button id="savePrompt-tplBtn2" ng-click="saveData(1)">Save</button>
<button id="savePrompt-tplBtn4" ng-click="saveData(2)">Don't Save</button>
<button id="savePrompt-tplBtn3" ng-click="saveData(3)">Cancel</button>
</div>
<button id="btnSlidingFeeschedule" ng-disabled="slidingfeedisable"
data-ng-click="slidingFeeScheduleClick();">Sliding Fee Schedule</button>
<button id="patient-demographicsBtn56" type="button"
ng-click="cmdOk_Click()">Save</button>
<button id="patient-demographicsBtn57" type="button"
ng-click="cancelbtn()">Cancel</button>
</div>
</div>
<div class="modal hide" id="slidingfeescheduleDailog">
<input id="slidingfeescheduleIpt34" data-ng-model="patientIncomeDetails.PovertyLevel">
<input id="slidingfeescheduleIpt35" data-ng-model="status.name">
<input id="slidingfeescheduleIpt37" data-ng-model="patientIncomeDetails.AssignedType">
<input id="slidingfeescheduleIpt40" data-ng-model="patientIncomeDetails.AssignedDate">
<input id="slidingfeescheduleIpt41" data-ng-model="patientIncomeDetails.ExpiryDate">
<input id="slidingfeescheduleIpt42" data--ng-model="patientIncomeDetails.FeeSchedule">
<button id="slidingfeescheduleBtn6" data-ng-click="assignSlidingFeeSchedule();">Assign</button>
<button id="slidingfeescheduleBtn8" type="button"
ng-click="closeSlidingFeeScheduleModal()">Close</button>
</div>
<script>
window.fixture = {disabled: false, values: null, prompt: false};
window.saved = false;
const $ = s => document.querySelector(s);
const show = (s, on) => $(s).classList.toggle('hide', !on);
const FIELDS = {
poverty_level: '#slidingfeescheduleIpt34', status: '#slidingfeescheduleIpt35',
scale_type: '#slidingfeescheduleIpt37', from_date: '#slidingfeescheduleIpt40',
to_date: '#slidingfeescheduleIpt41', fee_schedule: '#slidingfeescheduleIpt42',
};
$('#claimPatientInfo1790766147287').onclick = () => {
$('#btnSlidingFeeschedule').disabled = !!window.fixture.disabled;
setTimeout(() => show('#ptInfo', true), 300);
};
$('#btnSlidingFeeschedule').onclick = () => {
for (const s of Object.values(FIELDS)) $(s).value = '';
show('#slidingfeescheduleDailog', true);
const v = window.fixture.values;
if (v) setTimeout(() => {
for (const [k, s] of Object.entries(FIELDS)) $(s).value = v[k] || '';
}, 700);
};
$('#slidingfeescheduleBtn8').onclick = () => show('#slidingfeescheduleDailog', false);
$('#patient-demographicsBtn57').onclick = () => {
if (window.fixture.prompt) show('#savePrompt', true);
else show('#ptInfo', false);
};
$('#savePrompt-tplBtn4').onclick = () => {
show('#savePrompt', false); show('#ptInfo', false);
};
for (const s of ['#savePrompt-tplBtn2', '#patient-demographicsBtn56',
'#slidingfeescheduleBtn6'])
$(s).onclick = () => { window.saved = true; };
</script>
</body>
</html>
+458
View File
@@ -0,0 +1,458 @@
<!doctype html>
<!--
A faithful cut-down of the UB Claim modal eCW served on 2026-09-07.
Reproduced on purpose, rather than saved from the live page: the real form is
patient data and must never be committed. Everything the extractor reaches for
is here with the real attribute names, the real nesting, and — the point of the
whole fixture — the real **timestamped ids**.
The timestamp here is 9999999999999, deliberately different from the
1788790287089 of the captured DOM. Any selector that had the number baked in
would fail against this file, which is exactly what the test is for.
Also reproduced faithfully:
* the ICD code lives in an <input value="R69">, not in text
* the CPT grid is entirely inputs, ids ending in the row index
* eCW pads every grid with blank ng-repeat rows to hold its height
* the address text is ellipsised, with the full value in title=
-->
<html>
<body>
<div class="modal fade bluetheme ubClaimModalBackdrop in" id="UBClaimDiv9999999999999" style="display:block">
<div class="modal-dialog visible" id="UBClaimDiv">
<div id="UBClaimModalContent9999999999999" class="modal-content">
<div class="modal-header">
<button id="UBClaimBtn3" type="button" class="close">&times;</button>
<h4 class="modal-title" id="myModalLabel">UB Form Details
<span class="ml5 fs11 patient-identifier-span">SAMPLE, Pat Q &nbsp; May 11, 1979 (48 yo F) &nbsp; Acc No. 900123</span>
</h4>
</div>
<div class="modal-body">
<!-- patient strip -->
<div class="single-column middle">
<span class="blue_txt" ng-bind="showEllipsisForField(PatientInfo.namewithsuffix,25)" title="Sample, Pat, Q">Sample, Pat, Q</span>
<span class="blue_txt" ng-bind="' ' + PatientInfo.Age + ', ' + PatientInfo.patSex"> 48Y, F</span>
<span class="fnt11" ng-bind="PatientInfo.dob">05/11/1979</span>
<span class="fnt11" ng-bind="showEllipsisForField(PatientInfo.address +', '+ PatientInfo.address2 + ', ' + PatientInfo.state+ ' ' + PatientInfo.zip,45)" title="100 SAMPLE ST, , CO 80000-0000">100 SAMPLE ST, , CO 806...</span>
<span class="fnt11" ng-bind="PatientInfo.phone">555-010-0100</span>
Acct No : <span ng-bind="showEllipsisForField(PatientInfo.ControlNo,10)">900123</span>
</div>
<!-- header block -->
<table class="table section-table"><tbody><tr>
<td>
<table class="table"><tbody>
<tr>
<td><label>Claim No:</label></td>
<td class="w60p ubClaimNumberText"><span title="9104000">9104000</span></td>
</tr>
<tr>
<td><label>Claim Date</label></td>
<td><input type="text" class="form-control MMDDYYYYDatePicker hasDatepicker"
ng-model="ClaimData.ClaimDate" id="claimDate9999999999999"
value="06/29/2026" placeholder="MM/DD/YYYY"></td>
</tr>
</tbody></table>
</td>
<td>
<table class="table"><tbody>
<tr><td><label>Bill Type</label></td>
<td><input type="text" ng-model="Ub92Data.BillType" id="BillType" value="131"></td></tr>
</tbody></table>
</td>
<td>
<label>Facility:</label>
<input id="UBClaimIpt23" type="text" ng-model="selectApptFacilityData.facility.Name"
title="MWC:Brighton Womens Clinic" value="MWC:Brighton Womens Clinic" readonly>
<label>Copay</label>
<input type="text" id="ClaimDataCopay" ng-model="ClaimData.copay" value="0.00">
<label>Pt. Uncovered Amt:</label>
<input type="text" id="ClaimDataPtUnCovAmt" ng-model="ClaimData.PtUnCovAmt" value="0.00">
</td>
<td>
<label>Attending</label>
<input id="UBClaimIpt29" type="text" ng-model="ClaimData.PayToProviderName"
value="Clinician, Casey M" readonly>
<label>Claim Status</label>
<select id="claimStatusSel9999999999999" ng-model="selectedClaimStatusCodes" ng-change="claimStatusChanged()">
<option value="CMC">Ready to Submit (Electronic)</option>
<option value="113ME">Medcor Testing</option>
<option value="108ME" selected="selected">Medcor Ready</option>
<option value="CMS">Submitted</option>
</select>
</td>
</tr></tbody></table>
<!-- upper tabs -->
<ul id="UBClaimUl1" class="nav">
<li class="active"><a id="UBClaimLink4" href="javascript:void(0)" data-toggle="tab" data-target="#claimedi9999999999999">ICD, CPT and Revenue Codes</a></li>
<li><a id="UBClaimLink3" href="javascript:void(0)" data-toggle="tab" data-target="#inp9999999999999">Occurrence and Value Codes</a></li>
<li><a id="UBClaimLink2" href="javascript:void(0)" data-toggle="tab" data-target="#addinf9999999999999">Insurance and Payments</a></li>
<li><a id="UBClaimLink1" href="javascript:void(0)" data-toggle="tab" data-target="#icd9999999999999">Additional Information</a></li>
</ul>
<!-- Insurance and Payments pane -->
<div class="tab-pane" id="addinf9999999999999">
<table id="UBClaimTbl3" class="table table-bordered blue-fade-table">
<thead><tr>
<th style="width:30px"><div class="th-inner"></div></th>
<th><div class="th-inner">Bill To</div></th>
<th><div class="th-inner">Name</div></th>
<th><div class="th-inner">State</div></th>
<th><div class="th-inner">Subscriber No.</div></th>
<th><div class="th-inner">Rel</div></th>
<th><div class="th-inner">Insured</div></th>
<th><div class="th-inner">Group No.</div></th>
</tr></thead>
<tbody>
<tr ng-repeat="insurance in InvInsList">
<td><span ng-bind="insurance.sequanceNo">P</span></td>
<td><input id="UBClaimIpt1ngR0" type="checkbox" name="billto" checked></td>
<td><span ng-bind="insurance.InsName">BH COLORADO ACCESS</span></td>
<td><span ng-bind="insurance.InsState">CO</span></td>
<td><span ng-bind="insurance.SubscriberNo">J000000</span></td>
<td><span ng-bind="insurance.SubscriberRel">1</span></td>
<td><span ng-bind="insurance.SubscriberName">Sample, Pat, Q</span></td>
<td><span ng-bind="insurance.GroupNo"></span></td>
</tr>
<tr ng-repeat="temp in InvInsListBlankRows">
<td>&nbsp;</td><td></td><td></td><td></td><td></td><td></td><td></td><td></td>
</tr>
</tbody>
</table>
<table id="UBClaimTbl4" class="table table-bordered blue-fade-table">
<thead><tr>
<th><div class="th-inner">Id</div></th>
<th><div class="th-inner">Date</div></th>
<th><div class="th-inner">From</div></th>
<th><div class="th-inner">Allowed</div></th>
<th><div class="th-inner">Deduct</div></th>
<th><div class="th-inner">Coins</div></th>
<th><div class="th-inner">Copay</div></th>
<th><div class="th-inner">Paid</div></th>
<th><div class="th-inner">Adjust</div></th>
<th><div class="th-inner">Withheld</div></th>
<th><div class="th-inner">E</div></th>
</tr></thead>
<tbody>
<tr ng-repeat="PayAdjRef in PayAdjRefund">
<td ng-bind="PayAdjRef.id">2000001</td>
<td ng-bind="PayAdjRef.date">06/29/2026</td>
<td ng-bind="PayAdjRef.from">Patient</td>
<td class="text-right" ng-bind="PayAdjRef.allowed">0.00</td>
<td class="text-right" ng-bind="PayAdjRef.deduct">0.00</td>
<td class="text-right" ng-bind="PayAdjRef.coins">0.00</td>
<td class="text-right" ng-bind="PayAdjRef.copay">0.00</td>
<td class="text-right" ng-bind="PayAdjRef.paid">0.00</td>
<td class="text-right" ng-bind="PayAdjRef.adjust">0.00</td>
<td class="text-right" ng-bind="PayAdjRef.withheld">0.00</td>
<td></td>
</tr>
<tr ng-repeat="temp in PayAdjRefundBlankRows">
<td></td><td></td><td></td><td></td><td></td><td></td>
<td></td><td></td><td></td><td></td><td></td>
</tr>
</tbody>
</table>
</div>
<!-- ICD, CPT and Revenue pane -->
<div class="tab-pane active" id="claimedi9999999999999">
<div id="icdCodesTableDiv">
<table class="table table-bordered blue-fade-table" id="icdCodesTable">
<thead><tr>
<th class="text-center">#</th>
<th></th>
<th>Code</th>
<th>Name</th>
<th></th>
</tr></thead>
<tbody ng-model="ICDCodes">
<tr ng-repeat="icd in ICDCodes">
<td class="text-center"><span ng-bind="$index+1">1</span></td>
<td class="text-center"><span class="icd10-green">10</span></td>
<td title="R69"><input id="UBClaimIpt2ngR0" type="text"
class="input-xs editableTDText" value="R69"></td>
<td title="Illness, unspecified">Illness, unspecified</td>
<td class="text-center"><button id="UBClaimBtn1ngR0"></button></td>
</tr>
<tr id="2">
<td class="text-center">*</td>
<td></td>
<td><input type="text" ng-model="newICD" id="txtnewIcd" class="input-xs editableTDText"></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
</div>
<!-- Condition Codes FL 18-28, as the real form (Dom.txt, 2026-10-16):
select-claim-code inputs uBClaimCondtnCode1..11, no blur / change
handler. setConditionCodes([...]) fills them per test case. -->
<table class="table table-bordered blue-fade-table" id="example4">
<thead><tr><th colspan="11" class="text-center">Condition Codes</th></tr></thead>
<thead><tr><th>18</th><th>19</th><th>20</th><th>21</th><th>22</th><th>23</th>
<th>24</th><th>25</th><th>26</th><th>27</th><th>28</th></tr></thead>
<tbody><tr id="conditionCodeRow"></tr></tbody>
</table>
<script>
(function () {
var row = document.getElementById('conditionCodeRow');
for (var n = 1; n <= 11; n++) {
row.insertAdjacentHTML('beforeend',
'<td><select-claim-code field-id="uBClaimCondtnCode' + n + '" max-length="2"' +
' table-name="UB92_conditioncodes" search-record="Ub92Data.ConditionCode' + n + '">' +
'<div class="select-record"><div class="input-group">' +
'<input type="text" class="form-control editableTDText text-center" maxlength="2"' +
' id="uBClaimCondtnCode' + n + '" ng-model="searchRecord" ng-focus="loadCodes();"' +
' ng-keydown="validateKey($event);" ng-keyup="showCodes($event);">' +
'</div></div></select-claim-code></td>');
}
// A test sets this to have the box marked invalid on input, as
// select-claim-code's ng-class does for a code it does not know.
window.conditionCodeInvalid = false;
row.addEventListener('input', function (e) {
if (window.conditionCodeInvalid) e.target.classList.add('invalid');
});
window.setConditionCodes = function (codes) {
for (var n = 1; n <= 11; n++) {
document.getElementById('uBClaimCondtnCode' + n).value = codes[n - 1] || '';
}
};
})();
</script>
<!-- CPT / Revenue tabs -->
<ul class="nav">
<li class="active" id="liCptRev"><a class="cursor addBrdr" data-toggle="tab"
data-target="#cptRev9999999999999" ng-click="cptTabUpdate('cptRev')">CPT/Revenue Codes (1)</a></li>
<li id="liCPTHcpcs"><a class="cursor" data-toggle="tab"
data-target="#cptHCPCS9999999999999" ng-click="cptTabUpdate('cptHcpcs')">CPT/HCPCS (1)</a></li>
</ul>
<div class="tab-content claim-tab">
<div class="tab-pane active" id="cptRev9999999999999">
<table id="UBClaimTbl10" class="table table-bordered blue-fade-table">
<thead><tr>
<th class="text-center"></th>
<th>42 RV CC</th>
<th>43 Description</th>
<th>44 HCPCS/Rates</th>
<th>45 Srvc Date</th>
<th>46 Srvc Unit</th>
<th>47 Total Charges</th>
<th>48 Non Convered</th>
<th>49 </th>
</tr></thead>
<tbody>
<tr ng-repeat="cptdetails in UB92CPTDetails">
<td class="text-center">1</td>
<td>0900</td>
<td>Psychological Services</td>
<td>H0023 GT</td>
<td>06/29/2026</td>
<td>1</td>
<td class="text-right">74.00</td>
<td></td>
<td></td>
</tr>
<tr ng-repeat="temp in UB92CPTDetailsBlankRows">
<td></td><td>&nbsp;</td><td></td><td></td><td></td>
<td></td><td></td><td></td><td></td>
</tr>
</tbody>
</table>
<table id="UBClaimTbl11" class="table">
<thead><tr>
<th></th><th></th><th></th><th></th>
<th class="text-center">Total Charges </th>
<th class="text-right" ng-bind="TotalCharges">74.00</th>
<th></th><th></th>
</tr></thead>
</table>
</div>
<div class="tab-pane" id="cptHCPCS9999999999999">
<div class="allbrd cptTbl" id="CPTCodesDiv">
<table class="table table-bordered blue-fade-table" id="claimCPTCodesTable9999999999999">
<thead><tr>
<th class="text-center">#</th><th>&nbsp;</th><th>Code</th><th>POS</th><th>TOS</th>
<th>SDOS</th><th>EDOS</th><th>M1</th><th>M2</th><th>M3</th><th>M4</th>
<th>ICD1</th><th>ICD2</th><th>ICD3</th><th>ICD4</th><th>Units</th>
<th>Billed Fee</th><th>Pro Id</th>
</tr></thead>
<tbody>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_0">
<td class="text-center"><span ng-bind="$index + 1">1</span></td>
<td><input type="checkbox" id="claimCPTBillToInsChk0" checked></td>
<td title="Behavioral Health Outreach Service (TH)"><input id="uBClaimCPTCode0" type="text" value="H0023" readonly></td>
<td><input type="text" id="uBClaimPOS0" value="11"></td>
<td><input type="text" id="uBClaimTOS0" value="1"></td>
<td><input type="text" id="uBClaimSDOS0" value="06/29/2026"></td>
<td><input type="text" id="uBClaimEDOS0" value="06/29/2026"></td>
<td><input type="text" id="uBClaimMod10" value="GT"></td>
<td><input type="text" id="uBClaimMod20" value=""></td>
<td><input type="text" id="uBClaimMod30" value=""></td>
<td><input type="text" id="uBClaimMod40" value=""></td>
<td><input type="text" id="uBClaimICD10" value="1"></td>
<td><input type="text" id="uBClaimICD20" value=""></td>
<td><input type="text" id="uBClaimICD30" value=""></td>
<td><input type="text" id="uBClaimICD40" value=""></td>
<td><input type="text" id="uBClaimUnits0" value="1"></td>
<td title="74.00"><input type="text" id="uBClaimBillFee0" value="74.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_1">
<td class="text-center"><span>2</span></td>
<td><input type="checkbox" id="claimCPTBillToInsChk1" checked></td>
<td title="Psychiatric diagnostic evaluation"><input id="uBClaimCPTCode1" type="text" value="90791" readonly></td>
<td><input type="text" id="uBClaimPOS1" value="11"></td>
<td><input type="text" id="uBClaimTOS1" value="1"></td>
<td><input type="text" id="uBClaimSDOS1" value="06/30/2026"></td>
<td><input type="text" id="uBClaimEDOS1" value="06/30/2026"></td>
<td><input type="text" id="uBClaimMod11" value=""></td>
<td><input type="text" id="uBClaimMod21" value=""></td>
<td><input type="text" id="uBClaimMod31" value=""></td>
<td><input type="text" id="uBClaimMod41" value=""></td>
<td><input type="text" id="uBClaimICD11" value="1"></td>
<td><input type="text" id="uBClaimICD21" value=""></td>
<td><input type="text" id="uBClaimICD31" value=""></td>
<td><input type="text" id="uBClaimICD41" value=""></td>
<td><input type="text" id="uBClaimUnits1" value="2"></td>
<td title="150.00"><input type="text" id="uBClaimBillFee1" value="150.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<!-- the blank entry row eCW leaves at the bottom: no CPTROW_ id -->
<tr>
<td class="text-center">*</td>
<td class="text-center"><input type="checkbox" checked></td>
<td><input type="text" id="editableTDTextNewCPTcode" ng-model="newCPT"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<!-- bottom tabs: notes, error logs -->
<div class="tab-content error-claim-tab">
<div class="tab-pane active" id="tab19999999999999">
<label>Billing Notes</label>
<textarea class="form-control" ng-model="ClaimData.notes" id="ubClaimNotes">Awaiting coding review.</textarea>
<table id="UBClaimTbl15" class="table table-condensed">
<thead><tr><th colspan="2"><label>Patient Portion</label></th></tr></thead>
<tbody>
<tr><td>Charges</td><td class="text-right boldTd" ng-bind="InvBalances[0].PtResp">0.00</td></tr>
<tr><td>Payments ...</td><td class="text-right boldTd" ng-bind="InvBalances[0].PtPayment">0.00</td></tr>
<tr><td>Balance</td><td class="text-right boldTd" ng-bind="InvBalances[0].PtBalance">0.00</td></tr>
</tbody>
</table>
<table id="UBClaimTbl16" class="table table-condensed">
<thead><tr><th colspan="2"><label>Total</label></th></tr></thead>
<tbody>
<tr><td>Charges</td><td class="text-right boldTd" ng-bind="InvBalances[0].InvoiceAmount">224.00</td></tr>
<tr><td>Payments ...</td><td class="text-right boldTd" ng-bind="InvBalances[0].Payment">0.00</td></tr>
<tr><td>Balance</td><td class="text-right boldTd" ng-bind="InvBalances[0].Balance">224.00</td></tr>
</tbody>
</table>
</div>
<div class="tab-pane" id="tab29999999999999">
<table id="UBClaimTbl17" class="table table-bordered blue-fade-table">
<thead><tr>
<th class="text-center">Sl No</th>
<th class="text-center">Claim/Batch #</th>
<th class="text-center">Error</th>
<th>Actions</th>
<th>&nbsp;</th>
</tr></thead>
<tbody>
<!-- ngRepeat: chkError in ChkCurUB92Batch -->
</tbody>
</table>
</div>
</div>
</div><!-- /modal-body -->
<div class="grey-bg modal-footer">
<button id="UBClaimProgressNoteBtn" type="button" class="btn btn-lgrey btn-sm btn-xs pull-left"
ng-click="viewProgNote()">Prog. Notes</button>
<button id="UBClaimBtn17" type="button" class="btn btn-lgrey btn-sm btn-xs pull-right">Cancel</button>
<button id="UBClaimBtn18" type="button" class="btn btn-blue btn-sm btn-xs pull-right">OK</button>
</div>
</div></div></div>
<script>
// Prog. Notes opens the note in an IFRAME inside a modal, with Close on this
// parent page - which is how eCW actually serves it. The note is a whole
// printable document with its own <html>, so it cannot be inline.
//
// Reproduced faithfully because the split is the trap: reading this modal's
// innerText finds none of the note, and looking for Close inside the note
// finds nothing either. progress_note.find() walks the frames; close()
// clicks here. The ng-click typo "closeProgressNoteViwer" is eCW's own.
// Cancel and OK both hide the same backdrop eCW's real closeUBClaimScreen()
// / saveAllData(true) do — added so tests can prove the modal actually
// closes on both paths, not just that the button was clicked. Neither
// button did anything at all before this: the original fixture only ever
// needed to test reading, never closing.
document.getElementById('UBClaimBtn17').addEventListener('click', function () {
document.getElementById('UBClaimDiv9999999999999').style.display = 'none';
});
document.getElementById('UBClaimBtn18').addEventListener('click', function () {
document.getElementById('UBClaimDiv9999999999999').style.display = 'none';
});
// The real DOM (claim 9120000) carries ng-blur="updateCPTMod(...)" on every
// M1 input — Angular does not commit the modifier to CPTCodes[$index].mod1
// until that fires. Reproduced here as a data attribute, not real Angular,
// so a test can prove set_cpt_pos_modifier() actually blurs the field
// instead of just filling it and trusting the fill to be enough.
document.querySelectorAll('[id^="uBClaimMod1"]').forEach(function (el) {
el.addEventListener('blur', function () { el.dataset.blurred = '1'; });
});
document.getElementById('UBClaimProgressNoteBtn').addEventListener('click', function () {
var m = document.createElement('div');
m.className = 'modal in';
m.id = 'progressNoteViewerDiv9999999999999';
m.style.display = 'block';
m.innerHTML =
'<div class="modal-dialog"><div class="modal-content">'
+ '<div class="modal-header"><h4 class="modal-title">Progress Note</h4></div>'
+ '<div class="modal-body">'
+ '<iframe id="progressNoteFrame" src="progress_note.html" '
+ 'style="width:900px;height:400px;border:0"></iframe>'
+ '</div>'
+ '<div class="modal-footer">'
+ '<button type="button" class="btn btn-blue btn-sm btn-xs pull-right" '
+ 'ng-click="closeProgressNoteViwer()">Close</button>'
+ '</div>'
+ '</div></div>';
document.body.appendChild(m);
m.querySelector('[ng-click="closeProgressNoteViwer()"]')
.addEventListener('click', function () { m.style.display = 'none'; });
});
</script>
</body>
</html>
+506
View File
@@ -0,0 +1,506 @@
<!doctype html>
<!--
A cut-down UB Claim form carrying a VACCINE claim, for conditions
/vaccine_admin_codes.py (Charge Condition Document row 18).
Reproduced by hand, never saved from the live page: a real claim is
patient data and must never be committed. The per-open timestamp here is
7777777777777 — deliberately different from ub_claim.html's
9999999999999 and hcfa_claim.html's 8888888888888, so a selector that
had one baked in fails against the others.
What this fixture exists to reproduce:
* the UB form's CPT/HCPCS grid — `tr id="CPTROW_n"`, `uBClaim*<n>`
field ids, and the code cell's `title` holding eCW's HOVER text
("TETANUS DIPHTHERIA TOXOIDS AND ACELLULAR PERTUSSIS VACC", "PCV20"),
which is what extract() saves as a row's `description` and what the
condition recognises a vaccine by;
* each row's "Assign To Patient" checkbox (`ng-click="updateBillToIns(n)"`)
— only a CHECKED row is actually billed, so only checked vaccine and
admin rows count;
* the patient strip's DOB (`ng-bind="PatientInfo.dob"`) and age/sex
text (" 50Y, M" / " 12M 12D, F");
* the "Add" button + Fee Schedule picker, copied from hcfa_claim.html.
NOTE: that picker flow is live-verified on the "Claim"/HCFA and Dental
screens (claim 9109000), NOT yet on the UB form — it is here because
the condition calls the same `claim_form.add_cpt_row()` either way.
The default grid is an adult (DOB 01/02/1976, 50 on the 07/07/2026 date
of service), Medicaid, with three checked vaccines and NO admin code —
exactly the shape the condition fires on: 90732, 90746 and 90734, all on
the client's vaccine code list (2026-10-13; vaccines are recognised by
that list only, so the earlier 90677 / 90750 / 90715 here were replaced).
Tests reshape it with the helpers in the script block at the bottom
(seedCptRows, setPatient, setClaimDate, removeFromFeeSchedule, and the
window.feeScheduleOk* / window.units* behaviour flags documented there)
rather than keeping one fixture per scenario.
-->
<html>
<body>
<div class="modal fade bluetheme ubClaimModalBackdrop in" id="UBClaimDiv7777777777777" style="display:block">
<div class="modal-dialog visible" id="UBClaimDiv">
<div id="UBClaimModalContent7777777777777" class="modal-content">
<div class="modal-header">
<button id="UBClaimBtn3" type="button" class="close">&times;</button>
<h4 class="modal-title" id="myModalLabel">UB Form Details</h4>
</div>
<div class="modal-body">
<!-- patient strip -->
<div class="single-column middle">
<span class="blue_txt" ng-bind="showEllipsisForField(PatientInfo.namewithsuffix,25)" title="Doe, Jordan">Doe, Jordan</span>
<span class="blue_txt" id="patAgeSex" ng-bind="' ' + PatientInfo.Age + ', ' + PatientInfo.patSex"> 50Y, M</span>
<span class="fnt11" id="patDob" ng-bind="PatientInfo.dob">01/02/1976</span>
Acct No : <span ng-bind="showEllipsisForField(PatientInfo.ControlNo,10)">500001</span>
</div>
<table class="table section-table"><tbody><tr>
<td>
<table class="table"><tbody>
<tr>
<td><label>Claim No:</label></td>
<td class="w60p ubClaimNumberText"><span title="9113000">9113000</span></td>
</tr>
<tr>
<td><label>Claim Date</label></td>
<td><input type="text" id="claimDate7777777777777" ng-model="ClaimData.ClaimDate" value="07/07/2026"></td>
</tr>
</tbody></table>
</td>
<td><label>Bill Type</label><input type="text" ng-model="Ub92Data.BillType" id="BillType" value="131"></td>
</tr></tbody></table>
<!-- Insurance and Payments pane (shown, so extract() reads the payer) -->
<table id="UBClaimTbl3" class="table table-bordered blue-fade-table">
<thead><tr>
<th style="width:30px"><div class="th-inner"></div></th>
<th><div class="th-inner">Bill To</div></th>
<th><div class="th-inner">Name</div></th>
</tr></thead>
<tbody>
<tr ng-repeat="insurance in InvInsList">
<td><span ng-bind="insurance.sequanceNo">P</span></td>
<td><input type="checkbox" name="billto" checked></td>
<td><span ng-bind="insurance.InsName">Medicaid</span></td>
</tr>
</tbody>
</table>
<table class="table table-bordered blue-fade-table" id="icdCodesTable">
<thead><tr><th class="text-center">#</th><th></th><th>Code</th><th>Name</th><th></th></tr></thead>
<tbody ng-model="ICDCodes">
<tr ng-repeat="icd in ICDCodes">
<td class="text-center"><span>1</span></td><td></td>
<td title="Z00.00"><input type="text" value="Z00.00"></td>
<td title="Encounter for general adult medical examination">Encounter for general adult medical examination</td><td></td>
</tr>
<tr ng-repeat="icd in ICDCodes">
<td class="text-center"><span>2</span></td><td></td>
<td title="Z23"><input type="text" value="Z23"></td>
<td title="Encounter for immunization">Encounter for immunization</td><td></td>
</tr>
</tbody>
</table>
<ul class="nav">
<li id="liCptRev"><a class="cursor" data-toggle="tab" data-target="#cptRev7777777777777"
ng-click="cptTabUpdate('cptRev')">CPT/Revenue Codes</a></li>
<li class="active" id="liCPTHcpcs"><a class="cursor" data-toggle="tab" data-target="#cptHCPCS7777777777777"
ng-click="cptTabUpdate('cptHcpcs')">CPT/HCPCS</a></li>
</ul>
<!-- Not live-verified on the UB form — see the header comment. -->
<button id="ubClaimAddCPTBtn7777777777777" type="button" class="btn btn-lgrey btn-xs"
ng-click="addProcedureCode('');">Add</button>
<div class="tab-pane active" id="cptHCPCS7777777777777">
<div class="allbrd cptTbl" id="CPTCodesDiv">
<table class="table table-bordered blue-fade-table" id="claimCPTCodesTable7777777777777">
<thead><tr>
<th class="text-center">#</th><th>&nbsp;</th><th>Code</th><th>POS</th><th>TOS</th>
<th>SDOS</th><th>EDOS</th><th>M1</th><th>M2</th><th>M3</th><th>M4</th>
<th>ICD1</th><th>ICD2</th><th>ICD3</th><th>ICD4</th><th>Units</th>
<th>Billed Fee</th><th>Pro Id</th>
</tr></thead>
<tbody>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_0">
<td class="text-center"><span>1</span></td>
<td><input type="checkbox" id="claimCPTBillToInsChk77777777777770" ng-click="updateBillToIns(0)" ng-checked="cpt.BillToIns=='1'" checked></td>
<td title="PREVENTIVE VISIT EST AGE 40-64"><input id="uBClaimCPTCode0" type="text" value="99396" readonly></td>
<td><input type="text" id="uBClaimPOS0" value="11"></td>
<td><input type="text" id="uBClaimTOS0" value="1"></td>
<td><input type="text" id="uBClaimSDOS0" value="07/07/2026"></td>
<td><input type="text" id="uBClaimEDOS0" value="07/07/2026"></td>
<td><input type="text" id="uBClaimMod10" value=""></td>
<td><input type="text" id="uBClaimMod20" value=""></td>
<td><input type="text" id="uBClaimMod30" value=""></td>
<td><input type="text" id="uBClaimMod40" value=""></td>
<td><input type="text" id="uBClaimICD10" value="1"></td>
<td><input type="text" id="uBClaimICD20" value=""></td>
<td><input type="text" id="uBClaimICD30" value=""></td>
<td><input type="text" id="uBClaimICD40" value=""></td>
<td><input type="text" id="uBClaimUnits0" value="1" ng-blur="padZero($index);editCPTRow('UNITS')"></td>
<td title="250.00"><input type="text" id="uBClaimBillFee0" value="250.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_1">
<td class="text-center"><span>2</span></td>
<td><input type="checkbox" id="claimCPTBillToInsChk77777777777771" ng-click="updateBillToIns(1)" ng-checked="cpt.BillToIns=='1'" checked></td>
<td title="PNEUMOCOCCAL VACCINE"><input id="uBClaimCPTCode1" type="text" value="90732" readonly></td>
<td><input type="text" id="uBClaimPOS1" value="11"></td>
<td><input type="text" id="uBClaimTOS1" value="1"></td>
<td><input type="text" id="uBClaimSDOS1" value="07/07/2026"></td>
<td><input type="text" id="uBClaimEDOS1" value="07/07/2026"></td>
<td><input type="text" id="uBClaimMod11" value=""></td>
<td><input type="text" id="uBClaimMod21" value=""></td>
<td><input type="text" id="uBClaimMod31" value=""></td>
<td><input type="text" id="uBClaimMod41" value=""></td>
<td><input type="text" id="uBClaimICD11" value="2"></td>
<td><input type="text" id="uBClaimICD21" value=""></td>
<td><input type="text" id="uBClaimICD31" value=""></td>
<td><input type="text" id="uBClaimICD41" value=""></td>
<td><input type="text" id="uBClaimUnits1" value="1" ng-blur="padZero($index);editCPTRow('UNITS')"></td>
<td title="290.00"><input type="text" id="uBClaimBillFee1" value="290.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_2">
<td class="text-center"><span>3</span></td>
<td><input type="checkbox" id="claimCPTBillToInsChk77777777777772" ng-click="updateBillToIns(2)" ng-checked="cpt.BillToIns=='1'" checked></td>
<td title="HEPATITIS B VACCINE ADULT DOSAGE FOR INTRAMUSCULAR USE"><input id="uBClaimCPTCode2" type="text" value="90746" readonly></td>
<td><input type="text" id="uBClaimPOS2" value="11"></td>
<td><input type="text" id="uBClaimTOS2" value="1"></td>
<td><input type="text" id="uBClaimSDOS2" value="07/07/2026"></td>
<td><input type="text" id="uBClaimEDOS2" value="07/07/2026"></td>
<td><input type="text" id="uBClaimMod12" value=""></td>
<td><input type="text" id="uBClaimMod22" value=""></td>
<td><input type="text" id="uBClaimMod32" value=""></td>
<td><input type="text" id="uBClaimMod42" value=""></td>
<td><input type="text" id="uBClaimICD12" value="2"></td>
<td><input type="text" id="uBClaimICD22" value=""></td>
<td><input type="text" id="uBClaimICD32" value=""></td>
<td><input type="text" id="uBClaimICD42" value=""></td>
<td><input type="text" id="uBClaimUnits2" value="1" ng-blur="padZero($index);editCPTRow('UNITS')"></td>
<td title="240.00"><input type="text" id="uBClaimBillFee2" value="240.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<tr ng-repeat="cpt in CPTCodes" id="CPTROW_3">
<td class="text-center"><span>4</span></td>
<td><input type="checkbox" id="claimCPTBillToInsChk77777777777773" ng-click="updateBillToIns(3)" ng-checked="cpt.BillToIns=='1'" checked></td>
<td title="MENINGOCOCCAL VACCINE, IM"><input id="uBClaimCPTCode3" type="text" value="90734" readonly></td>
<td><input type="text" id="uBClaimPOS3" value="11"></td>
<td><input type="text" id="uBClaimTOS3" value="1"></td>
<td><input type="text" id="uBClaimSDOS3" value="07/07/2026"></td>
<td><input type="text" id="uBClaimEDOS3" value="07/07/2026"></td>
<td><input type="text" id="uBClaimMod13" value=""></td>
<td><input type="text" id="uBClaimMod23" value=""></td>
<td><input type="text" id="uBClaimMod33" value=""></td>
<td><input type="text" id="uBClaimMod43" value=""></td>
<td><input type="text" id="uBClaimICD13" value="2"></td>
<td><input type="text" id="uBClaimICD23" value=""></td>
<td><input type="text" id="uBClaimICD33" value=""></td>
<td><input type="text" id="uBClaimICD43" value=""></td>
<td><input type="text" id="uBClaimUnits3" value="1" ng-blur="padZero($index);editCPTRow('UNITS')"></td>
<td title="60.00"><input type="text" id="uBClaimBillFee3" value="60.00"></td>
<td><input type="text" value="" readonly></td>
</tr>
<!-- the blank entry row eCW leaves at the bottom: no CPTROW_ id -->
<tr id="cptEntryRow">
<td class="text-center">*</td>
<td class="text-center"><input type="checkbox" checked></td>
<td><input type="text" id="editableTDTextNewCPTcode" ng-model="newCPT"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td><input type="text"></td><td><input type="text"></td>
<td></td>
</tr>
</tbody>
</table>
</div>
</div>
</div><!-- /modal-body -->
<!-- eCW's shared Fee Schedule picker — same stable ids as hcfa_claim.html. -->
<div class="modal fade bluetheme" id="claimFeeScheduleModal" style="display:none">
<div class="modal-dialog"><div class="modal-content">
<div class="modal-header">
<button id="claimFeeScheduleBtn1" type="button" class="close">&times;</button>
<h4 class="modal-title">Fee Schedule</h4>
</div>
<div class="modal-body">
<table class="table table-bordered claimFSCPTTbl" id="example1">
<thead><tr><th>Id</th><th>CPT</th><th>Name</th><th>Fee</th></tr></thead>
<tbody id="claimFSCPTTblBody"></tbody>
</table>
</div>
<div class="modal-footer">
<input id="claimFeeScheduleIpt6" type="text" placeholder="Search CPT">
<button id="claimFeeScheduleBtn8" type="button">Cancel</button>
<button id="claimFeeSchOkBtn" type="button">OK</button>
</div>
</div></div>
</div>
<div class="grey-bg modal-footer">
<button id="UBClaimProgressNoteBtn" type="button" ng-click="viewProgNote()">Prog. Notes</button>
<button id="UBClaimBtn17" type="button">Cancel</button>
<button id="UBClaimBtn18" type="button">OK</button>
</div>
</div></div></div>
<script>
document.getElementById('UBClaimBtn17').addEventListener('click', function () {
document.getElementById('UBClaimDiv7777777777777').style.display = 'none';
});
document.getElementById('UBClaimBtn18').addEventListener('click', function () {
document.getElementById('UBClaimDiv7777777777777').style.display = 'none';
});
var CPT_TBODY = document.querySelector('#claimCPTCodesTable7777777777777 tbody');
var ENTRY_ROW = document.getElementById('cptEntryRow');
function esc(s) {
return String(s == null ? '' : s).replace(/&/g, '&amp;').replace(/"/g, '&quot;')
.replace(/</g, '&lt;');
}
// One UB-style CPTROW_<n>, the same markup as the static rows above.
// `r.noCheckbox` drops the "Assign To Patient" checkbox entirely — the
// shape extract() must report as billed: null, not false. `r.noFee`
// likewise drops the Billed Fee input — extract() must report
// billed_fee: null (never read), not "" (read and blank, i.e. zero).
function buildCptRow(n, r) {
var tr = document.createElement('tr');
tr.id = 'CPTROW_' + n;
tr.setAttribute('ng-repeat', 'cpt in CPTCodes');
var checked = r.checked === false ? '' : ' checked';
var box = r.noCheckbox ? '' :
'<input type="checkbox" id="claimCPTBillToInsChk7777777777777' + n + '"'
+ ' ng-click="updateBillToIns(' + n + ')" ng-checked="cpt.BillToIns==\'1\'"' + checked + '>';
var f = function (prefix, v) {
return '<td><input type="text" id="' + prefix + n + '" value="' + esc(v) + '"></td>';
};
tr.innerHTML =
'<td class="text-center"><span>' + (n + 1) + '</span></td>'
+ '<td>' + box + '</td>'
+ '<td title="' + esc(r.title) + '"><input id="uBClaimCPTCode' + n + '" type="text" value="'
+ esc(r.code) + '" readonly></td>'
+ f('uBClaimPOS', r.pos == null ? '11' : r.pos)
+ f('uBClaimTOS', '1')
+ f('uBClaimSDOS', r.sdos == null ? '07/07/2026' : r.sdos)
+ f('uBClaimEDOS', r.sdos == null ? '07/07/2026' : r.sdos)
+ f('uBClaimMod1', r.mod1 || '') + f('uBClaimMod2', '')
+ f('uBClaimMod3', '') + f('uBClaimMod4', '')
+ f('uBClaimICD1', r.icd1 == null ? '1' : r.icd1) + f('uBClaimICD2', r.icd2 || '')
+ f('uBClaimICD3', r.icd3 || '') + f('uBClaimICD4', r.icd4 || '')
+ '<td><input type="text" id="uBClaimUnits' + n + '" value="' + esc(r.units || '1') + '"'
+ ' ng-blur="padZero($index);editCPTRow(\'UNITS\')"'
+ (r.unitFee ? ' data-unit-fee="' + esc(r.unitFee) + '"' : '') + '></td>'
+ (r.noFee ? '<td></td>'
: '<td title="' + esc(r.fee || '0.00') + '"><input type="text" id="uBClaimBillFee' + n
+ '" value="' + esc(r.fee || '0.00') + '"></td>')
+ '<td><input type="text" value="" readonly></td>';
// Stand-in for eCW's own ng-blur="padZero($index);editCPTRow('UNITS')":
// re-price the line from its per-unit fee when Units loses focus, so a
// test reading the fee back proves the blur actually happened.
// window.unitsRepriceDelayMs makes the re-price land LATER (an async
// $http-style handler); window.unitsNoReprice makes it never land.
var units = tr.querySelector('[id^="uBClaimUnits"]');
units.addEventListener('blur', function () {
units.dataset.blurred = '1';
var per = parseFloat(units.dataset.unitFee || '');
var qty = parseFloat(units.value || '0');
if (window.unitsNoReprice || isNaN(per) || isNaN(qty)) return;
var reprice = function () {
tr.querySelector('[id^="uBClaimBillFee"]').value = (per * qty).toFixed(2);
};
if (window.unitsRepriceDelayMs) setTimeout(reprice, window.unitsRepriceDelayMs);
else reprice();
});
return tr;
}
function cptRowCount() {
return CPT_TBODY.querySelectorAll('tr[id^="CPTROW_"]').length;
}
// Replace every CPTROW_ with `rows` (objects of buildCptRow's shape).
window.seedCptRows = function (rows) {
CPT_TBODY.querySelectorAll('tr[id^="CPTROW_"]').forEach(function (tr) { tr.remove(); });
rows.forEach(function (r, i) { CPT_TBODY.insertBefore(buildCptRow(i, r), ENTRY_ROW); });
};
window.setPatient = function (dob, ageSex) {
document.getElementById('patDob').textContent = dob;
document.getElementById('patAgeSex').textContent = ageSex;
};
window.setClaimDate = function (d) {
document.getElementById('claimDate7777777777777').value = d;
};
// The Fee Schedule picker, copied from hcfa_claim.html: a seed catalog,
// filtered "Starts With" the way the real picker defaults to. The decoy
// 904711 starts with 90471, so a search for 90471 lists both — proving
// add_cpt_row() picks the EXACT match, not the first row.
var feeScheduleCatalog = [
{id: '610001', code: '90460', name: 'IMMUNIZATION ADMIN THROUGH 18 YRS 1ST COMPONENT', fee: '25.00'},
{id: '610002', code: '90461', name: 'IMMUNIZATION ADMIN THROUGH 18 YRS EACH ADD COMPONENT', fee: '15.00'},
{id: '610003', code: '90471', name: 'IMMUNIZATION ADMIN SINGLE OR COMBINATION', fee: '30.00'},
{id: '610004', code: '90472', name: 'IMMUNIZATION ADMIN, EACH ADD', fee: '20.00'},
{id: '610005', code: '96372', name: 'THER/PROPH/DIAG INJ SC/IM', fee: '25.00'},
// PPS Codes (#25). G0467H is left out on purpose: a PPS Code the
// picker cannot find.
{id: '610010', code: 'G0466', name: 'FQHC VISIT, NEW PATIENT', fee: '180.00'},
{id: '610011', code: 'G0467', name: 'FQHC VISIT, ESTABLISHED PATIENT', fee: '150.00'},
{id: '610012', code: 'G0467NH', name: 'FQHC VISIT, ESTABLISHED, NURSING HOME', fee: '150.00'},
{id: '610013', code: 'G0468', name: 'FQHC VISIT, IPPE OR AWV', fee: '200.00'},
{id: '610099', code: '904711', name: 'Unrelated decoy code', fee: '99.00'},
];
var feeScheduleSelected = null;
// Tests take a code out of the catalog to make its add fail the way a
// missing fee-schedule entry would on the live picker.
// Tests re-price a code in the catalog — e.g. to 0.00, a Fee Schedule
// entry with no fee, so an added admin line comes back unpriced.
window.setFeeScheduleFee = function (code, fee) {
feeScheduleCatalog.forEach(function (r) { if (r.code === code) r.fee = fee; });
};
window.removeFromFeeSchedule = function (code) {
feeScheduleCatalog = feeScheduleCatalog.filter(function (r) { return r.code !== code; });
};
// Tests set this to make OK close the picker WITHOUT adding a row, the
// shape add_cpt_row() cannot tell from success on its own when the same
// code already sits on the claim (e.g. an unchecked 90460).
window.feeScheduleOkAddsNothing = false;
// More ways the live picker's OK has not been verified NOT to behave,
// each one a shape the condition must report rather than hide:
// feeScheduleOkKeepsOpen — OK does nothing, the picker stays up
// (eCW's own validation holding it open);
// feeScheduleOkRechecksExisting — OK re-checks and re-prices the claim's
// existing UNCHECKED line for the code
// instead of appending a new one;
// feeScheduleInsertBeforeCode — the new line goes in ABOVE the first
// existing line with this code, not at
// the bottom (a sorted grid);
// feeScheduleOkAlsoAdds — OK also appends a line for this code
// (a second open keeping the first pick).
// feeScheduleNewLineUnits — the new line comes back with this Units
// (e.g. '0') instead of 1, priced to match,
// so the bot's Units write + re-price path
// runs (it writes Units only when eCW did
// not already give the new line 1).
window.feeScheduleOkKeepsOpen = false;
window.feeScheduleOkRechecksExisting = false;
window.feeScheduleNewLineUnits = null;
window.feeScheduleInsertBeforeCode = null;
window.feeScheduleOkAlsoAdds = null;
function renderFeeScheduleResults(filterText) {
var tbody = document.getElementById('claimFSCPTTblBody');
tbody.innerHTML = '';
var q = (filterText || '').toUpperCase();
feeScheduleCatalog
.filter(function (row) { return row.code.toUpperCase().indexOf(q) === 0; })
.forEach(function (row) {
var tr = document.createElement('tr');
tr.innerHTML =
'<td>' + row.id + '</td>'
+ '<td><span>' + row.code + '</span></td>'
+ '<td>' + row.name + '</td>'
+ '<td>' + row.fee + '</td>';
tr.addEventListener('click', function () { feeScheduleSelected = row; });
tbody.appendChild(tr);
});
}
document.getElementById('ubClaimAddCPTBtn7777777777777').addEventListener('click', function () {
feeScheduleSelected = null;
document.getElementById('claimFeeScheduleIpt6').value = '';
renderFeeScheduleResults('');
document.getElementById('claimFeeScheduleModal').style.display = 'block';
});
document.getElementById('claimFeeScheduleIpt6').addEventListener('input', function () {
renderFeeScheduleResults(this.value);
});
document.getElementById('claimFeeScheduleBtn8').addEventListener('click', function () {
document.getElementById('claimFeeScheduleModal').style.display = 'none';
});
// OK appends a row the way eCW's own addClaimFSCPTCode('save') does —
// including filling POS, dates and the ICD pointers ITSELF (faked here by
// copying the claim's first line). The bot never hand-fills those; a test
// proves the added row keeps exactly what this "eCW" put there.
function rowsWithCode(code) {
return Array.prototype.filter.call(
CPT_TBODY.querySelectorAll('tr[id^="CPTROW_"]'),
function (tr) { return tr.querySelector('[id^="uBClaimCPTCode"]').value === code; });
}
function appendFromCatalog(row) {
var first = CPT_TBODY.querySelector('tr[id^="CPTROW_"]');
var copy = function (prefix) {
var e = first ? first.querySelector('[id^="' + prefix + '"]') : null;
return e ? e.value : '';
};
var newUnits = window.feeScheduleNewLineUnits || '1';
var anchor = ENTRY_ROW;
if (window.feeScheduleInsertBeforeCode) {
var hits = rowsWithCode(window.feeScheduleInsertBeforeCode);
if (hits.length) anchor = hits[0];
}
CPT_TBODY.insertBefore(buildCptRow(cptRowCount(), {
code: row.code, title: row.name, checked: true,
pos: copy('uBClaimPOS'), sdos: copy('uBClaimSDOS'),
icd1: copy('uBClaimICD1'), icd2: copy('uBClaimICD2'),
icd3: copy('uBClaimICD3'), icd4: copy('uBClaimICD4'),
units: newUnits, unitFee: row.fee,
fee: newUnits === '1' ? row.fee
: (parseFloat(row.fee) * parseFloat(newUnits || '0')).toFixed(2),
}), anchor);
}
document.getElementById('claimFeeSchOkBtn').addEventListener('click', function () {
if (window.feeScheduleOkKeepsOpen) return;
document.getElementById('claimFeeScheduleModal').style.display = 'none';
if (!feeScheduleSelected || window.feeScheduleOkAddsNothing) return;
var row = feeScheduleSelected;
if (window.feeScheduleOkRechecksExisting) {
var old = rowsWithCode(row.code).filter(function (tr) {
var box = tr.querySelector('[ng-click*="updateBillToIns("]');
return box && !box.checked;
})[0];
if (old) {
old.querySelector('[ng-click*="updateBillToIns("]').checked = true;
old.querySelector('[id^="uBClaimBillFee"]').value = row.fee;
return;
}
}
appendFromCatalog(row);
if (window.feeScheduleOkAlsoAdds) {
var extra = feeScheduleCatalog.filter(function (r) {
return r.code === window.feeScheduleOkAlsoAdds;
})[0];
// only on a LATER pick of a different code — the stale first pick
if (extra && extra.code !== row.code) appendFromCatalog(extra);
}
});
</script>
</body>
</html>