@mindbill/angular 0.17.0 → 0.18.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -55,6 +55,10 @@ export class CaseBillingComponent {
55
55
 
56
56
  `MindBillBillSubmissionComponent` marks required fields, scrolls to invalid input, resolves ZIP codes to city and state with an inline status line, searches the MindBill claims-administrator and ICD-10 directories as you type, calculates service-line totals, and uploads attachments. Dates use a masked MM/DD/YYYY input that accepts ISO, US, or bare-digit entry, normalizes the display once a complete date is typed, and submits ISO values — identical to the React form. On success, render `MindBillBillLifecycleComponent` with the returned bill ID. The lifecycle component loads its own immutable bill snapshot, status, EORs, payments, history, and available actions.
57
57
 
58
+ Billing providers can use `taxIdType: "EIN" | "SSN"` (EIN is the default). SSN inputs are password fields. For a provider already saved in MindBill, pass `billingProvider: { savedProviderId: "synthetic_provider_id" }` instead of copying its masked tax ID into the form. Corrections and duplicates of an existing SSN bill use `{ sourceBillId: "synthetic_bill_id" }` to preserve that bill's immutable provider snapshot. The component preserves either reference through submission; MindBill resolves the sensitive identifier server-side within the same organization. A user must explicitly choose **Enter a different billing provider** before replacing that reference with manually entered fields. Existing hosts that access billing-provider fields directly should narrow the union with `"name" in bill.billingProvider` first.
59
+
60
+ `MindBillOrganizationOnboardingComponent` supports EIN and encrypted saved SSN profiles. Saved SSNs return only their last four digits and configured state: leave the input blank to preserve an existing SSN, enter a value to replace it, or use **Clear saved SSN** to request removal on the next save. Changing the tax ID type resets the input rather than silently reinterpreting the previous identifier. Save/completion events contain the returned profile, not the submitted plaintext SSN. Never log or persist manually entered sensitive form state in host telemetry.
61
+
58
62
  When the lifecycle is rejected, it automatically renders the full ordered list of clearinghouse issues with actionable descriptions, acknowledgement codes, and sent/rejected timestamps. For custom layouts, use the same standalone surface directly:
59
63
 
60
64
  ```html
@@ -1,6 +1,6 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { signal, computed, Input, Component, EventEmitter, Output, inject, ChangeDetectorRef, HostListener, effect, Directive } from '@angular/core';
3
- import { createBillLifecycleClient, createBillReferenceClient, defaultBillReviewPayerOption, createBillSubmissionClient, REPORT_BILL_STATUS_OPTIONS, reportBillStatusContacts, BILL_TASKS_AGING_BUCKETS, createOrganizationClient } from '@mindbill/browser';
3
+ import { createBillLifecycleClient, createBillReferenceClient, defaultBillReviewPayerOption, createBillSubmissionClient, REPORT_BILL_STATUS_OPTIONS, reportBillStatusContacts, BILL_TASKS_AGING_BUCKETS, createOrganizationClient, organizationTaxIdWrite } from '@mindbill/browser';
4
4
  export { REPORT_BILL_STATUS_OPTIONS, defaultBillReviewPayerOption, reportBillStatusContacts } from '@mindbill/browser';
5
5
  import * as i1 from '@angular/common';
6
6
  import { CommonModule } from '@angular/common';
@@ -579,6 +579,20 @@ class MindBillBillSubmissionComponent {
579
579
  submissionError = new EventEmitter();
580
580
  billChange = new EventEmitter();
581
581
  bill = {};
582
+ get inlineBillingProvider() {
583
+ const provider = this.bill.billingProvider;
584
+ return provider && 'name' in provider ? provider : null;
585
+ }
586
+ setBillingTaxIdType(type) {
587
+ const provider = this.inlineBillingProvider;
588
+ if (!provider || (provider.taxIdType ?? 'EIN') === type)
589
+ return;
590
+ provider.taxIdType = type;
591
+ provider.taxId = '';
592
+ }
593
+ useManualBillingProvider() {
594
+ this.bill.billingProvider = { name: '', taxId: '', taxIdType: 'EIN', npi: '', phone: '', address: { line1: '', city: '', state: '', postalCode: '' } };
595
+ }
582
596
  workingAttachments = [];
583
597
  payerQuery = "";
584
598
  payerResults = [];
@@ -895,12 +909,20 @@ class MindBillBillSubmissionComponent {
895
909
  ["claim.claimsAdministrator", this.bill.claim.claimsAdministrator.id],
896
910
  ["claim.claimsAdministrator.payerId", !this.payerSelectionRequired || this.bill.claim.claimsAdministrator.payerId],
897
911
  ["diagnoses", this.bill.diagnoses.length],
898
- ["billingProvider.name", this.bill.billingProvider.name], ["billingProvider.taxId", this.bill.billingProvider.taxId], ["billingProvider.npi", this.bill.billingProvider.npi], ["billingProvider.phone", this.bill.billingProvider.phone],
899
- ["billingProvider.address.line1", this.bill.billingProvider.address.line1], ["billingProvider.address.city", this.bill.billingProvider.address.city], ["billingProvider.address.state", this.bill.billingProvider.address.state], ["billingProvider.address.postalCode", this.bill.billingProvider.address.postalCode],
900
912
  ["renderingProvider.name", this.bill.renderingProvider.name], ["renderingProvider.npi", this.bill.renderingProvider.npi], ["renderingProvider.taxonomy", this.bill.renderingProvider.taxonomy],
901
913
  ["serviceLocation.placeOfServiceCode", this.bill.serviceLocation.placeOfServiceCode], ["serviceLocation.address.line1", this.bill.serviceLocation.address.line1], ["serviceLocation.address.city", this.bill.serviceLocation.address.city], ["serviceLocation.address.state", this.bill.serviceLocation.address.state], ["serviceLocation.address.postalCode", this.bill.serviceLocation.address.postalCode],
902
914
  ["serviceLines", this.bill.serviceLines.some((line) => required(line.code) && (line.units ?? 1) > 0)],
903
915
  ];
916
+ const provider = this.bill.billingProvider;
917
+ if ('savedProviderId' in provider) {
918
+ candidates.push(['billingProvider.savedProviderId', provider.savedProviderId]);
919
+ }
920
+ else if ('sourceBillId' in provider) {
921
+ candidates.push(['billingProvider.sourceBillId', provider.sourceBillId]);
922
+ }
923
+ else {
924
+ candidates.push(['billingProvider.name', provider.name], ['billingProvider.taxId', provider.taxId], ['billingProvider.npi', provider.npi], ['billingProvider.phone', provider.phone], ['billingProvider.address.line1', provider.address.line1], ['billingProvider.address.city', provider.address.city], ['billingProvider.address.state', provider.address.state], ['billingProvider.address.postalCode', provider.address.postalCode]);
925
+ }
904
926
  this.invalidFields = new Set(candidates.filter(([, value]) => !value || !required(value)).map(([path]) => path));
905
927
  if (this.invalidFields.size) {
906
928
  this.errorMessage = `Complete ${this.invalidFields.size} highlighted required field${this.invalidFields.size === 1 ? "" : "s"} before submitting.`;
@@ -1014,14 +1036,19 @@ class MindBillBillSubmissionComponent {
1014
1036
 
1015
1037
  <fieldset id="mbs-provider"><legend>Providers &amp; place of service</legend><div class="grid">
1016
1038
  <h3 class="wide">Billing provider</h3>
1017
- <label [class.invalid]="bad('billingProvider.name')">Billing provider name <b>*</b><input name="billingProvider" [(ngModel)]="bill.billingProvider.name"></label>
1018
- <label [class.invalid]="bad('billingProvider.taxId')">Tax ID <b>*</b><input name="taxId" [(ngModel)]="bill.billingProvider.taxId"></label>
1019
- <label [class.invalid]="bad('billingProvider.npi')">Billing NPI <b>*</b><input name="billingNpi" [(ngModel)]="bill.billingProvider.npi" inputmode="numeric" maxlength="10"></label>
1020
- <label [class.invalid]="bad('billingProvider.phone')">Billing phone <b>*</b><input name="billingPhone" type="tel" [(ngModel)]="bill.billingProvider.phone"></label>
1021
- <label class="wide" [class.invalid]="bad('billingProvider.address.line1')">Billing address <b>*</b><input name="billingAddress" [(ngModel)]="bill.billingProvider.address.line1"></label>
1022
- <label [class.invalid]="bad('billingProvider.address.postalCode')">Billing ZIP <b>*</b><input name="billingZip" [(ngModel)]="bill.billingProvider.address.postalCode" inputmode="numeric"></label>
1023
- <label [class.invalid]="bad('billingProvider.address.city')">Billing city <b>*</b><input name="billingCity" [(ngModel)]="bill.billingProvider.address.city"></label>
1024
- <label [class.invalid]="bad('billingProvider.address.state')">Billing state <b>*</b><input name="billingState" [(ngModel)]="bill.billingProvider.address.state" maxlength="2"></label>
1039
+ @if (inlineBillingProvider; as provider) {
1040
+ <label [class.invalid]="bad('billingProvider.name')">Billing provider name <b>*</b><input name="billingProvider" [(ngModel)]="provider.name"></label>
1041
+ <label>Tax ID type<select name="taxIdType" [ngModel]="provider.taxIdType ?? 'EIN'" (ngModelChange)="setBillingTaxIdType($event)"><option value="EIN">EIN</option><option value="SSN">SSN</option></select></label>
1042
+ <label [class.invalid]="bad('billingProvider.taxId')">{{ provider.taxIdType === 'SSN' ? 'SSN' : 'EIN' }} <b>*</b><input name="taxId" [(ngModel)]="provider.taxId" [type]="provider.taxIdType === 'SSN' ? 'password' : 'text'" autocomplete="off" inputmode="numeric"></label>
1043
+ <label [class.invalid]="bad('billingProvider.npi')">Billing NPI <b>*</b><input name="billingNpi" [(ngModel)]="provider.npi" inputmode="numeric" maxlength="10"></label>
1044
+ <label [class.invalid]="bad('billingProvider.phone')">Billing phone <b>*</b><input name="billingPhone" type="tel" [(ngModel)]="provider.phone"></label>
1045
+ <label class="wide" [class.invalid]="bad('billingProvider.address.line1')">Billing address <b>*</b><input name="billingAddress" [(ngModel)]="provider.address.line1"></label>
1046
+ <label [class.invalid]="bad('billingProvider.address.postalCode')">Billing ZIP <b>*</b><input name="billingZip" [(ngModel)]="provider.address.postalCode" inputmode="numeric"></label>
1047
+ <label [class.invalid]="bad('billingProvider.address.city')">Billing city <b>*</b><input name="billingCity" [(ngModel)]="provider.address.city"></label>
1048
+ <label [class.invalid]="bad('billingProvider.address.state')">Billing state <b>*</b><input name="billingState" [(ngModel)]="provider.address.state" maxlength="2"></label>
1049
+ } @else {
1050
+ <div class="wide" [class.invalid]="bad('billingProvider.savedProviderId') || bad('billingProvider.sourceBillId')"><span>Using a saved billing provider</span><small>The saved tax ID is resolved securely when you submit, without returning the SSN to this form.</small><div class="quick"><button type="button" (click)="useManualBillingProvider()">Enter a different billing provider</button></div></div>
1051
+ }
1025
1052
  <h3 class="wide">Rendering provider</h3>
1026
1053
  <label [class.invalid]="bad('renderingProvider.name')">Rendering provider name <b>*</b><input name="renderingProvider" [(ngModel)]="bill.renderingProvider.name"></label>
1027
1054
  <label [class.invalid]="bad('renderingProvider.npi')">Rendering provider NPI <b>*</b><input name="renderingNpi" [(ngModel)]="bill.renderingProvider.npi" inputmode="numeric" maxlength="10"></label>
@@ -1073,7 +1100,7 @@ class MindBillBillSubmissionComponent {
1073
1100
  <div class="submit-row"><span>{{ invalidFields.size ? 'Complete the highlighted required fields.' : 'All required billing data is ready.' }}</span><button type="submit" [disabled]="submitting">{{ submitting ? 'Submitting…' : submitLabel }}</button></div>
1074
1101
  @if (dragActive) { <div class="drop-overlay" aria-hidden="true"><div><strong>Drop PDFs to attach</strong><span>Supporting documents are added to this submission.</span></div></div> }
1075
1102
  </form>
1076
- `, isInline: true, styles: [":host{display:block}.mbs{--danger:#c83c3c;font-family:var(--font);color:var(--t)}*{box-sizing:border-box}.intro{display:flex;justify-content:space-between;align-items:start;margin:0 0 24px}.intro h2{margin:0;font-size:24px;font-weight:600}.intro p{margin:6px 0 0;color:var(--m)}.intro>span{color:var(--m);font-size:13px}.mbs b{color:inherit}.intro b,label>b,.lookup>label>b,.diagnosis>label>b,.cell>label>b{color:var(--danger)}fieldset{border:1px solid var(--b);border-radius:var(--r);margin:0 0 22px;padding:24px 26px 26px;background:var(--s)}legend{padding:0 10px;font-size:18px;font-weight:700}.grid{display:grid;grid-template-columns:1fr 1fr;gap:20px 28px}.wide{grid-column:1/-1}h3{margin:4px 0 -4px;padding-top:12px;border-top:1px solid var(--b);font-size:16px}h3:first-child{border:0;padding-top:0}label,.lookup,.diagnosis{display:grid;gap:8px;font-size:14px;font-weight:700}.grid>label{display:flex;flex-wrap:wrap;align-content:start;align-items:center;column-gap:4px;row-gap:8px}.grid>label>input,.grid>label>select,.grid>label>small,.grid>label>mindbill-date-input{flex:0 0 100%}.grid>div.wide{display:grid;gap:8px;font-size:14px;font-weight:700}input,select{width:100%;min-height:46px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus,select:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}.invalid input,.invalid select,.invalid-set{border-color:var(--danger)!important;background:color-mix(in srgb,var(--danger) 4%,var(--s))}.invalid>label{color:var(--danger)}small{color:var(--m);font-weight:450}.selected{color:#238655}.options{position:relative;z-index:4;max-height:300px;overflow:auto;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);box-shadow:0 14px 35px #172b3730}.options button{display:grid;width:100%;gap:3px;border:0;border-bottom:1px solid var(--b);background:var(--s);padding:12px 14px;text-align:left;color:var(--t);cursor:pointer}.options button:hover{background:color-mix(in srgb,var(--a) 7%,var(--s))}.options span{color:var(--m);font-size:12px}.quick,.chips{display:flex;flex-wrap:wrap;gap:8px}.quick button,.chips button{border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 11px;color:var(--t);font:inherit;font-size:13px;cursor:pointer}.quick .on{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.chips button{border-color:color-mix(in srgb,var(--a) 40%,var(--b));background:color-mix(in srgb,var(--a) 7%,var(--s));font-weight:700}.dx{display:flex;flex-wrap:wrap;gap:5px;padding-top:6px}.dx button{width:30px;height:30px;border:1px solid var(--b);border-radius:8px;background:var(--s);color:var(--m);font:inherit;font-size:13px;font-weight:750;cursor:pointer;padding:0}.dx button.on{border-color:var(--a);background:color-mix(in srgb,var(--a) 10%,var(--s));color:var(--a)}.line-head,.service-line{display:grid;grid-template-columns:1.5fr 1.35fr .8fr .5fr .7fr 36px;gap:14px;align-items:start}.line-head{padding:0 0 9px;color:var(--m);font-size:12px;font-weight:700}.service-line{border-top:1px solid var(--b);padding:12px 0}.service-line label,.service-line .cell{display:grid;gap:6px;font-size:14px;font-weight:700}.service-line strong{text-align:right;padding-top:12px}.remove{border:0;background:transparent;color:var(--m);font-size:25px;cursor:pointer}.mobile-label{display:none}.total{display:flex;justify-content:flex-end;gap:36px;border-top:1px solid var(--b);padding-top:14px;font-size:17px}.attachment{display:flex;align-items:center;justify-content:space-between;gap:16px;border:1px solid var(--b);border-radius:var(--cr);margin-bottom:10px;padding:14px 16px}.attachment.locked{border-color:#9fd6b4;background:#f3fcf6}.attachment>div:first-child{display:grid;gap:4px}.attachment span{color:var(--m);font-size:13px}.attachment-actions{display:flex;gap:8px}.attachment button{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:8px 12px;color:var(--t);font-weight:700;cursor:pointer}.dropzone{position:relative;display:grid;min-height:170px;place-content:center;gap:8px;border:2px dashed color-mix(in srgb,var(--m) 60%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;transition:border-color .15s,background .15s}.dropzone.drag-active{border-color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.dropzone input{position:absolute;inset:0;opacity:0;cursor:pointer}.dropzone span{color:var(--m);font-weight:450}.drop-overlay{position:fixed;inset:0;z-index:60;display:grid;place-content:center;background:color-mix(in srgb,var(--a) 14%,#ffffffd9);pointer-events:none}.drop-overlay div{display:grid;gap:6px;border:2px dashed var(--a);border-radius:var(--r);background:var(--s);padding:34px 44px;text-align:center;box-shadow:0 24px 60px #172b3740}.drop-overlay strong{font-size:19px}.drop-overlay span{color:var(--m)}.error{margin:0 0 14px;border-left:4px solid var(--danger);border-radius:var(--cr);background:color-mix(in srgb,var(--danger) 10%,var(--s));padding:14px;color:var(--danger)}.submit-row{position:sticky;bottom:0;z-index:3;display:flex;align-items:center;justify-content:space-between;border:1px solid var(--b);border-radius:var(--r);background:color-mix(in srgb,var(--s) 96%,transparent);box-shadow:0 -8px 24px #172b3718;padding:14px 18px}.submit-row>span{color:#43835f}.submit-row button{min-width:190px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 24px;font:inherit;font-weight:800;cursor:pointer}.submit-row button:disabled{opacity:.6;cursor:wait}@media(max-width:760px){fieldset{padding:18px 16px}.grid{grid-template-columns:1fr}.wide{grid-column:auto}.intro{display:grid;gap:10px}.line-head{display:none}.service-line{grid-template-columns:1fr 1fr}.service-line>*{grid-column:1/-1}.service-line label:nth-child(3){grid-column:1}.service-line>strong{grid-column:2;grid-row:3;text-align:left}.service-line>.remove{grid-column:1/-1}.mobile-label{display:block;color:var(--m);font-size:12px}.attachment{align-items:flex-start}.attachment-actions{align-items:center}.submit-row>span{display:none}.submit-row button{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MindBillComboBoxComponent, selector: "mindbill-combo-box", inputs: ["value", "placeholder", "options", "disabled", "loading", "loadingMore", "invalid", "preserveValueOnOpen", "ariaLabel", "createOption"], outputs: ["opened", "queryChange", "endReached", "selected"] }, { kind: "component", type: MindBillDateInputComponent, selector: "mindbill-date-input", inputs: ["value", "disabled", "ariaLabel"], outputs: ["valueChange"] }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }] });
1103
+ `, isInline: true, styles: [":host{display:block}.mbs{--danger:#c83c3c;font-family:var(--font);color:var(--t)}*{box-sizing:border-box}.intro{display:flex;justify-content:space-between;align-items:start;margin:0 0 24px}.intro h2{margin:0;font-size:24px;font-weight:600}.intro p{margin:6px 0 0;color:var(--m)}.intro>span{color:var(--m);font-size:13px}.mbs b{color:inherit}.intro b,label>b,.lookup>label>b,.diagnosis>label>b,.cell>label>b{color:var(--danger)}fieldset{border:1px solid var(--b);border-radius:var(--r);margin:0 0 22px;padding:24px 26px 26px;background:var(--s)}legend{padding:0 10px;font-size:18px;font-weight:700}.grid{display:grid;grid-template-columns:1fr 1fr;gap:20px 28px}.wide{grid-column:1/-1}h3{margin:4px 0 -4px;padding-top:12px;border-top:1px solid var(--b);font-size:16px}h3:first-child{border:0;padding-top:0}label,.lookup,.diagnosis{display:grid;gap:8px;font-size:14px;font-weight:700}.grid>label{display:flex;flex-wrap:wrap;align-content:start;align-items:center;column-gap:4px;row-gap:8px}.grid>label>input,.grid>label>select,.grid>label>small,.grid>label>mindbill-date-input{flex:0 0 100%}.grid>div.wide{display:grid;gap:8px;font-size:14px;font-weight:700}input,select{width:100%;min-height:46px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus,select:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}.invalid input,.invalid select,.invalid-set{border-color:var(--danger)!important;background:color-mix(in srgb,var(--danger) 4%,var(--s))}.invalid>label{color:var(--danger)}small{color:var(--m);font-weight:450}.selected{color:#238655}.options{position:relative;z-index:4;max-height:300px;overflow:auto;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);box-shadow:0 14px 35px #172b3730}.options button{display:grid;width:100%;gap:3px;border:0;border-bottom:1px solid var(--b);background:var(--s);padding:12px 14px;text-align:left;color:var(--t);cursor:pointer}.options button:hover{background:color-mix(in srgb,var(--a) 7%,var(--s))}.options span{color:var(--m);font-size:12px}.quick,.chips{display:flex;flex-wrap:wrap;gap:8px}.quick button,.chips button{border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 11px;color:var(--t);font:inherit;font-size:13px;cursor:pointer}.quick .on{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.chips button{border-color:color-mix(in srgb,var(--a) 40%,var(--b));background:color-mix(in srgb,var(--a) 7%,var(--s));font-weight:700}.dx{display:flex;flex-wrap:wrap;gap:5px;padding-top:6px}.dx button{width:30px;height:30px;border:1px solid var(--b);border-radius:8px;background:var(--s);color:var(--m);font:inherit;font-size:13px;font-weight:750;cursor:pointer;padding:0}.dx button.on{border-color:var(--a);background:color-mix(in srgb,var(--a) 10%,var(--s));color:var(--a)}.line-head,.service-line{display:grid;grid-template-columns:1.5fr 1.35fr .8fr .5fr .7fr 36px;gap:14px;align-items:start}.line-head{padding:0 0 9px;color:var(--m);font-size:12px;font-weight:700}.service-line{border-top:1px solid var(--b);padding:12px 0}.service-line label,.service-line .cell{display:grid;gap:6px;font-size:14px;font-weight:700}.service-line strong{text-align:right;padding-top:12px}.remove{border:0;background:transparent;color:var(--m);font-size:25px;cursor:pointer}.mobile-label{display:none}.total{display:flex;justify-content:flex-end;gap:36px;border-top:1px solid var(--b);padding-top:14px;font-size:17px}.attachment{display:flex;align-items:center;justify-content:space-between;gap:16px;border:1px solid var(--b);border-radius:var(--cr);margin-bottom:10px;padding:14px 16px}.attachment.locked{border-color:#9fd6b4;background:#f3fcf6}.attachment>div:first-child{display:grid;gap:4px}.attachment span{color:var(--m);font-size:13px}.attachment-actions{display:flex;gap:8px}.attachment button{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:8px 12px;color:var(--t);font-weight:700;cursor:pointer}.dropzone{position:relative;display:grid;min-height:170px;place-content:center;gap:8px;border:2px dashed color-mix(in srgb,var(--m) 60%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;transition:border-color .15s,background .15s}.dropzone.drag-active{border-color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.dropzone input{position:absolute;inset:0;opacity:0;cursor:pointer}.dropzone span{color:var(--m);font-weight:450}.drop-overlay{position:fixed;inset:0;z-index:60;display:grid;place-content:center;background:color-mix(in srgb,var(--a) 14%,#ffffffd9);pointer-events:none}.drop-overlay div{display:grid;gap:6px;border:2px dashed var(--a);border-radius:var(--r);background:var(--s);padding:34px 44px;text-align:center;box-shadow:0 24px 60px #172b3740}.drop-overlay strong{font-size:19px}.drop-overlay span{color:var(--m)}.error{margin:0 0 14px;border-left:4px solid var(--danger);border-radius:var(--cr);background:color-mix(in srgb,var(--danger) 10%,var(--s));padding:14px;color:var(--danger)}.submit-row{position:sticky;bottom:0;z-index:3;display:flex;align-items:center;justify-content:space-between;border:1px solid var(--b);border-radius:var(--r);background:color-mix(in srgb,var(--s) 96%,transparent);box-shadow:0 -8px 24px #172b3718;padding:14px 18px}.submit-row>span{color:#43835f}.submit-row button{min-width:190px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 24px;font:inherit;font-weight:800;cursor:pointer}.submit-row button:disabled{opacity:.6;cursor:wait}@media(max-width:760px){fieldset{padding:18px 16px}.grid{grid-template-columns:1fr}.wide{grid-column:auto}.intro{display:grid;gap:10px}.line-head{display:none}.service-line{grid-template-columns:1fr 1fr}.service-line>*{grid-column:1/-1}.service-line label:nth-child(3){grid-column:1}.service-line>strong{grid-column:2;grid-row:3;text-align:left}.service-line>.remove{grid-column:1/-1}.mobile-label{display:block;color:var(--m);font-size:12px}.attachment{align-items:flex-start}.attachment-actions{align-items:center}.submit-row>span{display:none}.submit-row button{width:100%}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i2.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MindBillComboBoxComponent, selector: "mindbill-combo-box", inputs: ["value", "placeholder", "options", "disabled", "loading", "loadingMore", "invalid", "preserveValueOnOpen", "ariaLabel", "createOption"], outputs: ["opened", "queryChange", "endReached", "selected"] }, { kind: "component", type: MindBillDateInputComponent, selector: "mindbill-date-input", inputs: ["value", "disabled", "ariaLabel"], outputs: ["valueChange"] }, { kind: "pipe", type: i1.CurrencyPipe, name: "currency" }] });
1077
1104
  }
1078
1105
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillBillSubmissionComponent, decorators: [{
1079
1106
  type: Component,
@@ -1123,14 +1150,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1123
1150
 
1124
1151
  <fieldset id="mbs-provider"><legend>Providers &amp; place of service</legend><div class="grid">
1125
1152
  <h3 class="wide">Billing provider</h3>
1126
- <label [class.invalid]="bad('billingProvider.name')">Billing provider name <b>*</b><input name="billingProvider" [(ngModel)]="bill.billingProvider.name"></label>
1127
- <label [class.invalid]="bad('billingProvider.taxId')">Tax ID <b>*</b><input name="taxId" [(ngModel)]="bill.billingProvider.taxId"></label>
1128
- <label [class.invalid]="bad('billingProvider.npi')">Billing NPI <b>*</b><input name="billingNpi" [(ngModel)]="bill.billingProvider.npi" inputmode="numeric" maxlength="10"></label>
1129
- <label [class.invalid]="bad('billingProvider.phone')">Billing phone <b>*</b><input name="billingPhone" type="tel" [(ngModel)]="bill.billingProvider.phone"></label>
1130
- <label class="wide" [class.invalid]="bad('billingProvider.address.line1')">Billing address <b>*</b><input name="billingAddress" [(ngModel)]="bill.billingProvider.address.line1"></label>
1131
- <label [class.invalid]="bad('billingProvider.address.postalCode')">Billing ZIP <b>*</b><input name="billingZip" [(ngModel)]="bill.billingProvider.address.postalCode" inputmode="numeric"></label>
1132
- <label [class.invalid]="bad('billingProvider.address.city')">Billing city <b>*</b><input name="billingCity" [(ngModel)]="bill.billingProvider.address.city"></label>
1133
- <label [class.invalid]="bad('billingProvider.address.state')">Billing state <b>*</b><input name="billingState" [(ngModel)]="bill.billingProvider.address.state" maxlength="2"></label>
1153
+ @if (inlineBillingProvider; as provider) {
1154
+ <label [class.invalid]="bad('billingProvider.name')">Billing provider name <b>*</b><input name="billingProvider" [(ngModel)]="provider.name"></label>
1155
+ <label>Tax ID type<select name="taxIdType" [ngModel]="provider.taxIdType ?? 'EIN'" (ngModelChange)="setBillingTaxIdType($event)"><option value="EIN">EIN</option><option value="SSN">SSN</option></select></label>
1156
+ <label [class.invalid]="bad('billingProvider.taxId')">{{ provider.taxIdType === 'SSN' ? 'SSN' : 'EIN' }} <b>*</b><input name="taxId" [(ngModel)]="provider.taxId" [type]="provider.taxIdType === 'SSN' ? 'password' : 'text'" autocomplete="off" inputmode="numeric"></label>
1157
+ <label [class.invalid]="bad('billingProvider.npi')">Billing NPI <b>*</b><input name="billingNpi" [(ngModel)]="provider.npi" inputmode="numeric" maxlength="10"></label>
1158
+ <label [class.invalid]="bad('billingProvider.phone')">Billing phone <b>*</b><input name="billingPhone" type="tel" [(ngModel)]="provider.phone"></label>
1159
+ <label class="wide" [class.invalid]="bad('billingProvider.address.line1')">Billing address <b>*</b><input name="billingAddress" [(ngModel)]="provider.address.line1"></label>
1160
+ <label [class.invalid]="bad('billingProvider.address.postalCode')">Billing ZIP <b>*</b><input name="billingZip" [(ngModel)]="provider.address.postalCode" inputmode="numeric"></label>
1161
+ <label [class.invalid]="bad('billingProvider.address.city')">Billing city <b>*</b><input name="billingCity" [(ngModel)]="provider.address.city"></label>
1162
+ <label [class.invalid]="bad('billingProvider.address.state')">Billing state <b>*</b><input name="billingState" [(ngModel)]="provider.address.state" maxlength="2"></label>
1163
+ } @else {
1164
+ <div class="wide" [class.invalid]="bad('billingProvider.savedProviderId') || bad('billingProvider.sourceBillId')"><span>Using a saved billing provider</span><small>The saved tax ID is resolved securely when you submit, without returning the SSN to this form.</small><div class="quick"><button type="button" (click)="useManualBillingProvider()">Enter a different billing provider</button></div></div>
1165
+ }
1134
1166
  <h3 class="wide">Rendering provider</h3>
1135
1167
  <label [class.invalid]="bad('renderingProvider.name')">Rendering provider name <b>*</b><input name="renderingProvider" [(ngModel)]="bill.renderingProvider.name"></label>
1136
1168
  <label [class.invalid]="bad('renderingProvider.npi')">Rendering provider NPI <b>*</b><input name="renderingNpi" [(ngModel)]="bill.renderingProvider.npi" inputmode="numeric" maxlength="10"></label>
@@ -1900,8 +1932,9 @@ function correctionBill(data) {
1900
1932
  claimsAdministrator: { id: data.injury.claimsAdminId || "", name: data.injury.claimsAdminName || "" },
1901
1933
  },
1902
1934
  service: { date: data.bill.dos, ...(data.bill.dosEnd !== undefined ? { endDate: data.bill.dosEnd } : {}), ...(data.bill.authorizationNumber !== undefined ? { authorizationNumber: data.bill.authorizationNumber } : {}) },
1903
- billingProvider: {
1935
+ billingProvider: billing?.taxIdType === 'SSN' && billing.taxIdConfigured ? { sourceBillId: data.bill.id } : {
1904
1936
  name: billing?.name || "", taxId: billing?.taxId || "", npi: billing?.npi || "", phone: billing?.phone || "",
1937
+ ...(billing?.taxIdType ? { taxIdType: billing.taxIdType } : {}),
1905
1938
  address: { line1: billing?.billingStreet || "", city: billing?.billingCity || "", state: billing?.billingState || "", postalCode: billing?.billingZip || "" },
1906
1939
  },
1907
1940
  renderingProvider: {
@@ -2634,7 +2667,7 @@ class MindBillOrganizationOnboardingComponent {
2634
2667
  step = "practice";
2635
2668
  saving = false;
2636
2669
  saved = {};
2637
- identity = { name: "", legalName: "", taxId: "", npi: "", phone: "", email: "" };
2670
+ identity = { name: "", legalName: "", taxId: "", taxIdType: "EIN", npi: "", phone: "", email: "" };
2638
2671
  provider = { name: "", taxId: "", npi: "", billType: "Professional", phone: "", billingStreet: "", billingCity: "", billingState: "", billingZip: "" };
2639
2672
  locations = [{ name: "", street: "", city: "", state: "", zip: "", isPrimary: false }];
2640
2673
  w9File = null;
@@ -2669,12 +2702,15 @@ class MindBillOrganizationOnboardingComponent {
2669
2702
  adoptProfile(profile) {
2670
2703
  this.profile = profile;
2671
2704
  this.identity = {
2672
- name: profile.practiceIdentity.name ?? this.identity.name,
2673
- legalName: profile.practiceIdentity.legalName ?? this.identity.legalName,
2674
- taxId: profile.practiceIdentity.taxId ?? this.identity.taxId,
2675
- npi: profile.practiceIdentity.npi ?? this.identity.npi,
2676
- phone: profile.practiceIdentity.phone ?? this.identity.phone,
2677
- email: profile.practiceIdentity.email ?? this.identity.email,
2705
+ name: profile.practiceIdentity.name ?? this.identity.name ?? '',
2706
+ legalName: profile.practiceIdentity.legalName ?? this.identity.legalName ?? '',
2707
+ taxId: profile.practiceIdentity.taxId ?? '',
2708
+ taxIdType: profile.practiceIdentity.taxIdType ?? 'EIN',
2709
+ taxIdLast4: profile.practiceIdentity.taxIdLast4 ?? '',
2710
+ taxIdConfigured: profile.practiceIdentity.taxIdConfigured ?? false,
2711
+ npi: profile.practiceIdentity.npi ?? this.identity.npi ?? '',
2712
+ phone: profile.practiceIdentity.phone ?? this.identity.phone ?? '',
2713
+ email: profile.practiceIdentity.email ?? this.identity.email ?? '',
2678
2714
  };
2679
2715
  if (profile.billingProviders[0])
2680
2716
  this.provider = { billType: "Professional", ...profile.billingProviders[0] };
@@ -2721,12 +2757,23 @@ class MindBillOrganizationOnboardingComponent {
2721
2757
  }
2722
2758
  savePractice() {
2723
2759
  void this.run(() => this.client.saveBillingProfile({
2724
- practiceIdentity: this.identity,
2725
- ...(this.provider.name.trim() || this.provider.taxId.trim() || this.provider.npi.trim()
2726
- ? { billingProviders: [this.provider] }
2760
+ practiceIdentity: organizationTaxIdWrite(this.identity),
2761
+ ...(this.provider.id || this.provider.name.trim() || this.provider.taxId?.trim() || this.provider.npi.trim()
2762
+ ? { billingProviders: [organizationTaxIdWrite(this.provider)] }
2727
2763
  : {}),
2728
2764
  }), "practice");
2729
2765
  }
2766
+ setTaxIdType(value, type) {
2767
+ if ((value.taxIdType ?? 'EIN') === type)
2768
+ return;
2769
+ value.taxIdType = type;
2770
+ this.clearTaxId(value);
2771
+ }
2772
+ clearTaxId(value) {
2773
+ value.taxId = '';
2774
+ value.taxIdLast4 = '';
2775
+ value.taxIdConfigured = false;
2776
+ }
2730
2777
  saveLocations() {
2731
2778
  void this.run(() => this.client.saveLocations(this.locations.filter((item) => item.name.trim() || item.street.trim())), "locations");
2732
2779
  }
@@ -2756,7 +2803,10 @@ class MindBillOrganizationOnboardingComponent {
2756
2803
  <div class="grid">
2757
2804
  <label>Practice name<input [(ngModel)]="identity.name" [disabled]="saving"></label>
2758
2805
  <label>Legal name<input [(ngModel)]="identity.legalName" [disabled]="saving"></label>
2759
- <label>Tax ID (EIN)<input [(ngModel)]="identity.taxId" placeholder="94-1234567" [disabled]="saving"></label>
2806
+ <label>Practice tax ID type<select [ngModel]="identity.taxIdType ?? 'EIN'" (ngModelChange)="setTaxIdType(identity, $event)" [disabled]="saving"><option value="EIN">EIN</option><option value="SSN">SSN</option></select></label>
2807
+ <div class="tax-id"><label>{{ identity.taxIdType === 'SSN' ? 'Practice SSN' : 'Practice EIN' }}<input [(ngModel)]="identity.taxId" [type]="identity.taxIdType === 'SSN' ? 'password' : 'text'" autocomplete="off" inputmode="numeric" [disabled]="saving"></label>
2808
+ @if (identity.taxIdType === 'SSN' && identity.taxIdConfigured) { <small>SSN ending in {{ identity.taxIdLast4 }} is saved. Leave blank to keep it, or enter a replacement.</small><button type="button" class="add" [disabled]="saving" (click)="clearTaxId(identity)">Clear saved practice SSN</button> }
2809
+ </div>
2760
2810
  <label>Group NPI<input [(ngModel)]="identity.npi" [disabled]="saving"></label>
2761
2811
  <label>Phone<input [(ngModel)]="identity.phone" [disabled]="saving"></label>
2762
2812
  <label>Email<input [(ngModel)]="identity.email" [disabled]="saving"></label>
@@ -2764,7 +2814,10 @@ class MindBillOrganizationOnboardingComponent {
2764
2814
  <h3>Billing provider (pay-to)</h3>
2765
2815
  <div class="grid">
2766
2816
  <label>Billing provider name<input [(ngModel)]="provider.name" [disabled]="saving"></label>
2767
- <label>Billing tax ID<input [(ngModel)]="provider.taxId" [disabled]="saving"></label>
2817
+ <label>Billing tax ID type<select [ngModel]="provider.taxIdType ?? 'EIN'" (ngModelChange)="setTaxIdType(provider, $event)" [disabled]="saving"><option value="EIN">EIN</option><option value="SSN">SSN</option></select></label>
2818
+ <div class="tax-id"><label>{{ provider.taxIdType === 'SSN' ? 'Billing SSN' : 'Billing EIN' }}<input [(ngModel)]="provider.taxId" [type]="provider.taxIdType === 'SSN' ? 'password' : 'text'" autocomplete="off" inputmode="numeric" [disabled]="saving"></label>
2819
+ @if (provider.taxIdType === 'SSN' && provider.taxIdConfigured) { <small>SSN ending in {{ provider.taxIdLast4 }} is saved. Leave blank to keep it, or enter a replacement.</small><button type="button" class="add" [disabled]="saving" (click)="clearTaxId(provider)">Clear saved billing SSN</button> }
2820
+ </div>
2768
2821
  <label>Billing NPI<input [(ngModel)]="provider.npi" [disabled]="saving"></label>
2769
2822
  <label>Billing phone<input [(ngModel)]="provider.phone" [disabled]="saving"></label>
2770
2823
  <label class="span">Street<input [(ngModel)]="provider.billingStreet" [disabled]="saving"></label>
@@ -2819,7 +2872,7 @@ class MindBillOrganizationOnboardingComponent {
2819
2872
  @if (errorMessage) { <div class="error" role="alert">{{ errorMessage }}</div> }
2820
2873
  </div>
2821
2874
  </section>
2822
- `, isInline: true, styles: [":host{display:block}.mbob{font-family:var(--font);color:var(--t);font-size:15px}.mbob *{box-sizing:border-box}.card{border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:24px}header{margin-bottom:18px}header h2{margin:0;font-size:22px}header p{margin:5px 0 0;color:var(--m)}.steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.steps button{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 13px;color:var(--m);font:inherit;font-size:13px;font-weight:700;cursor:pointer}.steps button.active{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.steps button.done i{color:#159447;font-style:normal}.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.span{grid-column:1/-1}label{display:grid;gap:7px;font-size:13px;font-weight:720}input:not([type=radio]):not([type=file]){width:100%;min-height:44px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}h3{margin:20px 0 12px;padding-top:16px;border-top:1px solid var(--b);font-size:15px}.loc{display:grid;grid-template-columns:1.2fr 1.4fr .9fr .4fr .6fr auto auto;gap:10px;align-items:end;border-top:1px solid color-mix(in srgb,var(--b) 60%,transparent);padding:12px 0}.loc:first-of-type{border-top:0}.primary{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--m);white-space:nowrap;padding-bottom:12px}.remove{border:0;background:transparent;color:var(--m);font-size:20px;cursor:pointer;padding-bottom:8px}.add{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 14px;color:var(--t);font:inherit;font-weight:700;cursor:pointer}.drop{display:grid;place-content:center;gap:6px;min-height:150px;border:2px dashed color-mix(in srgb,var(--m) 55%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;position:relative}.drop input{position:absolute;inset:0;opacity:0;cursor:pointer}.drop span{color:var(--m);font-size:13px}.w9-current{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #9fd6b4;border-radius:var(--cr);background:#f3fcf6;padding:12px 14px;margin-bottom:14px}.w9-current span{color:var(--m);font-size:13px}.check{display:grid;gap:9px}.check-item{display:flex;align-items:center;gap:10px;border:1px solid var(--b);border-radius:var(--cr);padding:11px 14px}.check-item.complete{border-color:#9fd6b4;background:#f3fcf6}.check-item i{font-style:normal}.actions{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:20px}.actions>span{color:var(--m)}.save{min-width:170px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 22px;font:inherit;font-weight:780;cursor:pointer}.save:disabled{opacity:.6;cursor:wait}.error{margin-top:14px;border-left:4px solid #c83c3c;border-radius:var(--cr);background:color-mix(in srgb,#c83c3c 8%,var(--s));padding:12px 14px;color:#c83c3c}.done-copy{color:#159447;font-weight:750}.muted{color:var(--m)}@media(max-width:820px){.grid{grid-template-columns:1fr}.span{grid-column:auto}.loc{grid-template-columns:1fr 1fr;align-items:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
2875
+ `, isInline: true, styles: [":host{display:block}.mbob{font-family:var(--font);color:var(--t);font-size:15px}.mbob *{box-sizing:border-box}.card{border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:24px}header{margin-bottom:18px}header h2{margin:0;font-size:22px}header p{margin:5px 0 0;color:var(--m)}.steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.steps button{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 13px;color:var(--m);font:inherit;font-size:13px;font-weight:700;cursor:pointer}.steps button.active{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.steps button.done i{color:#159447;font-style:normal}.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.span{grid-column:1/-1}label{display:grid;gap:7px;font-size:13px;font-weight:720}input:not([type=radio]):not([type=file]),select{width:100%;min-height:44px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus,select:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}.tax-id{display:grid;gap:7px;align-content:start}.tax-id small{color:var(--m);font-size:12px}.tax-id button{justify-self:start}h3{margin:20px 0 12px;padding-top:16px;border-top:1px solid var(--b);font-size:15px}.loc{display:grid;grid-template-columns:1.2fr 1.4fr .9fr .4fr .6fr auto auto;gap:10px;align-items:end;border-top:1px solid color-mix(in srgb,var(--b) 60%,transparent);padding:12px 0}.loc:first-of-type{border-top:0}.primary{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--m);white-space:nowrap;padding-bottom:12px}.remove{border:0;background:transparent;color:var(--m);font-size:20px;cursor:pointer;padding-bottom:8px}.add{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 14px;color:var(--t);font:inherit;font-weight:700;cursor:pointer}.drop{display:grid;place-content:center;gap:6px;min-height:150px;border:2px dashed color-mix(in srgb,var(--m) 55%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;position:relative}.drop input{position:absolute;inset:0;opacity:0;cursor:pointer}.drop span{color:var(--m);font-size:13px}.w9-current{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #9fd6b4;border-radius:var(--cr);background:#f3fcf6;padding:12px 14px;margin-bottom:14px}.w9-current span{color:var(--m);font-size:13px}.check{display:grid;gap:9px}.check-item{display:flex;align-items:center;gap:10px;border:1px solid var(--b);border-radius:var(--cr);padding:11px 14px}.check-item.complete{border-color:#9fd6b4;background:#f3fcf6}.check-item i{font-style:normal}.actions{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:20px}.actions>span{color:var(--m)}.save{min-width:170px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 22px;font:inherit;font-weight:780;cursor:pointer}.save:disabled{opacity:.6;cursor:wait}.error{margin-top:14px;border-left:4px solid #c83c3c;border-radius:var(--cr);background:color-mix(in srgb,#c83c3c 8%,var(--s));padding:12px 14px;color:#c83c3c}.done-copy{color:#159447;font-weight:750}.muted{color:var(--m)}@media(max-width:820px){.grid{grid-template-columns:1fr}.span{grid-column:auto}.loc{grid-template-columns:1fr 1fr;align-items:center}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: i1.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "directive", type: i2.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] });
2823
2876
  }
2824
2877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillOrganizationOnboardingComponent, decorators: [{
2825
2878
  type: Component,
@@ -2841,7 +2894,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
2841
2894
  <div class="grid">
2842
2895
  <label>Practice name<input [(ngModel)]="identity.name" [disabled]="saving"></label>
2843
2896
  <label>Legal name<input [(ngModel)]="identity.legalName" [disabled]="saving"></label>
2844
- <label>Tax ID (EIN)<input [(ngModel)]="identity.taxId" placeholder="94-1234567" [disabled]="saving"></label>
2897
+ <label>Practice tax ID type<select [ngModel]="identity.taxIdType ?? 'EIN'" (ngModelChange)="setTaxIdType(identity, $event)" [disabled]="saving"><option value="EIN">EIN</option><option value="SSN">SSN</option></select></label>
2898
+ <div class="tax-id"><label>{{ identity.taxIdType === 'SSN' ? 'Practice SSN' : 'Practice EIN' }}<input [(ngModel)]="identity.taxId" [type]="identity.taxIdType === 'SSN' ? 'password' : 'text'" autocomplete="off" inputmode="numeric" [disabled]="saving"></label>
2899
+ @if (identity.taxIdType === 'SSN' && identity.taxIdConfigured) { <small>SSN ending in {{ identity.taxIdLast4 }} is saved. Leave blank to keep it, or enter a replacement.</small><button type="button" class="add" [disabled]="saving" (click)="clearTaxId(identity)">Clear saved practice SSN</button> }
2900
+ </div>
2845
2901
  <label>Group NPI<input [(ngModel)]="identity.npi" [disabled]="saving"></label>
2846
2902
  <label>Phone<input [(ngModel)]="identity.phone" [disabled]="saving"></label>
2847
2903
  <label>Email<input [(ngModel)]="identity.email" [disabled]="saving"></label>
@@ -2849,7 +2905,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
2849
2905
  <h3>Billing provider (pay-to)</h3>
2850
2906
  <div class="grid">
2851
2907
  <label>Billing provider name<input [(ngModel)]="provider.name" [disabled]="saving"></label>
2852
- <label>Billing tax ID<input [(ngModel)]="provider.taxId" [disabled]="saving"></label>
2908
+ <label>Billing tax ID type<select [ngModel]="provider.taxIdType ?? 'EIN'" (ngModelChange)="setTaxIdType(provider, $event)" [disabled]="saving"><option value="EIN">EIN</option><option value="SSN">SSN</option></select></label>
2909
+ <div class="tax-id"><label>{{ provider.taxIdType === 'SSN' ? 'Billing SSN' : 'Billing EIN' }}<input [(ngModel)]="provider.taxId" [type]="provider.taxIdType === 'SSN' ? 'password' : 'text'" autocomplete="off" inputmode="numeric" [disabled]="saving"></label>
2910
+ @if (provider.taxIdType === 'SSN' && provider.taxIdConfigured) { <small>SSN ending in {{ provider.taxIdLast4 }} is saved. Leave blank to keep it, or enter a replacement.</small><button type="button" class="add" [disabled]="saving" (click)="clearTaxId(provider)">Clear saved billing SSN</button> }
2911
+ </div>
2853
2912
  <label>Billing NPI<input [(ngModel)]="provider.npi" [disabled]="saving"></label>
2854
2913
  <label>Billing phone<input [(ngModel)]="provider.phone" [disabled]="saving"></label>
2855
2914
  <label class="span">Street<input [(ngModel)]="provider.billingStreet" [disabled]="saving"></label>
@@ -2904,7 +2963,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
2904
2963
  @if (errorMessage) { <div class="error" role="alert">{{ errorMessage }}</div> }
2905
2964
  </div>
2906
2965
  </section>
2907
- `, styles: [":host{display:block}.mbob{font-family:var(--font);color:var(--t);font-size:15px}.mbob *{box-sizing:border-box}.card{border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:24px}header{margin-bottom:18px}header h2{margin:0;font-size:22px}header p{margin:5px 0 0;color:var(--m)}.steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.steps button{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 13px;color:var(--m);font:inherit;font-size:13px;font-weight:700;cursor:pointer}.steps button.active{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.steps button.done i{color:#159447;font-style:normal}.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.span{grid-column:1/-1}label{display:grid;gap:7px;font-size:13px;font-weight:720}input:not([type=radio]):not([type=file]){width:100%;min-height:44px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}h3{margin:20px 0 12px;padding-top:16px;border-top:1px solid var(--b);font-size:15px}.loc{display:grid;grid-template-columns:1.2fr 1.4fr .9fr .4fr .6fr auto auto;gap:10px;align-items:end;border-top:1px solid color-mix(in srgb,var(--b) 60%,transparent);padding:12px 0}.loc:first-of-type{border-top:0}.primary{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--m);white-space:nowrap;padding-bottom:12px}.remove{border:0;background:transparent;color:var(--m);font-size:20px;cursor:pointer;padding-bottom:8px}.add{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 14px;color:var(--t);font:inherit;font-weight:700;cursor:pointer}.drop{display:grid;place-content:center;gap:6px;min-height:150px;border:2px dashed color-mix(in srgb,var(--m) 55%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;position:relative}.drop input{position:absolute;inset:0;opacity:0;cursor:pointer}.drop span{color:var(--m);font-size:13px}.w9-current{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #9fd6b4;border-radius:var(--cr);background:#f3fcf6;padding:12px 14px;margin-bottom:14px}.w9-current span{color:var(--m);font-size:13px}.check{display:grid;gap:9px}.check-item{display:flex;align-items:center;gap:10px;border:1px solid var(--b);border-radius:var(--cr);padding:11px 14px}.check-item.complete{border-color:#9fd6b4;background:#f3fcf6}.check-item i{font-style:normal}.actions{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:20px}.actions>span{color:var(--m)}.save{min-width:170px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 22px;font:inherit;font-weight:780;cursor:pointer}.save:disabled{opacity:.6;cursor:wait}.error{margin-top:14px;border-left:4px solid #c83c3c;border-radius:var(--cr);background:color-mix(in srgb,#c83c3c 8%,var(--s));padding:12px 14px;color:#c83c3c}.done-copy{color:#159447;font-weight:750}.muted{color:var(--m)}@media(max-width:820px){.grid{grid-template-columns:1fr}.span{grid-column:auto}.loc{grid-template-columns:1fr 1fr;align-items:center}}\n"] }]
2966
+ `, styles: [":host{display:block}.mbob{font-family:var(--font);color:var(--t);font-size:15px}.mbob *{box-sizing:border-box}.card{border:1px solid var(--b);border-radius:var(--r);background:var(--s);padding:24px}header{margin-bottom:18px}header h2{margin:0;font-size:22px}header p{margin:5px 0 0;color:var(--m)}.steps{display:flex;gap:8px;flex-wrap:wrap;margin-bottom:20px}.steps button{display:inline-flex;align-items:center;gap:7px;border:1px solid var(--b);border-radius:999px;background:var(--s);padding:7px 13px;color:var(--m);font:inherit;font-size:13px;font-weight:700;cursor:pointer}.steps button.active{border-color:var(--a);color:var(--a);background:color-mix(in srgb,var(--a) 8%,var(--s))}.steps button.done i{color:#159447;font-style:normal}.grid{display:grid;grid-template-columns:1fr 1fr;gap:16px 22px}.span{grid-column:1/-1}label{display:grid;gap:7px;font-size:13px;font-weight:720}input:not([type=radio]):not([type=file]),select{width:100%;min-height:44px;border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 12px;color:var(--t);font:inherit;font-weight:450}input:focus,select:focus{outline:3px solid color-mix(in srgb,var(--a) 22%,transparent);border-color:var(--a)}.tax-id{display:grid;gap:7px;align-content:start}.tax-id small{color:var(--m);font-size:12px}.tax-id button{justify-self:start}h3{margin:20px 0 12px;padding-top:16px;border-top:1px solid var(--b);font-size:15px}.loc{display:grid;grid-template-columns:1.2fr 1.4fr .9fr .4fr .6fr auto auto;gap:10px;align-items:end;border-top:1px solid color-mix(in srgb,var(--b) 60%,transparent);padding:12px 0}.loc:first-of-type{border-top:0}.primary{display:inline-flex;align-items:center;gap:6px;font-size:12px;color:var(--m);white-space:nowrap;padding-bottom:12px}.remove{border:0;background:transparent;color:var(--m);font-size:20px;cursor:pointer;padding-bottom:8px}.add{border:1px solid var(--b);border-radius:var(--cr);background:var(--s);padding:10px 14px;color:var(--t);font:inherit;font-weight:700;cursor:pointer}.drop{display:grid;place-content:center;gap:6px;min-height:150px;border:2px dashed color-mix(in srgb,var(--m) 55%,transparent);border-radius:var(--cr);text-align:center;cursor:pointer;position:relative}.drop input{position:absolute;inset:0;opacity:0;cursor:pointer}.drop span{color:var(--m);font-size:13px}.w9-current{display:flex;align-items:center;justify-content:space-between;gap:12px;border:1px solid #9fd6b4;border-radius:var(--cr);background:#f3fcf6;padding:12px 14px;margin-bottom:14px}.w9-current span{color:var(--m);font-size:13px}.check{display:grid;gap:9px}.check-item{display:flex;align-items:center;gap:10px;border:1px solid var(--b);border-radius:var(--cr);padding:11px 14px}.check-item.complete{border-color:#9fd6b4;background:#f3fcf6}.check-item i{font-style:normal}.actions{display:flex;justify-content:space-between;align-items:center;gap:14px;margin-top:20px}.actions>span{color:var(--m)}.save{min-width:170px;border:0;border-radius:var(--cr);background:var(--a);color:var(--ac);padding:12px 22px;font:inherit;font-weight:780;cursor:pointer}.save:disabled{opacity:.6;cursor:wait}.error{margin-top:14px;border-left:4px solid #c83c3c;border-radius:var(--cr);background:color-mix(in srgb,#c83c3c 8%,var(--s));padding:12px 14px;color:#c83c3c}.done-copy{color:#159447;font-weight:750}.muted{color:var(--m)}@media(max-width:820px){.grid{grid-template-columns:1fr}.span{grid-column:auto}.loc{grid-template-columns:1fr 1fr;align-items:center}}\n"] }]
2908
2967
  }], propDecorators: { appearance: [{
2909
2968
  type: Input
2910
2969
  }], sessionEndpoint: [{