@mindbill/angular 0.16.1 → 0.18.0

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.
@@ -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>
@@ -1248,11 +1280,12 @@ class MindBillBillLifecycleComponent {
1248
1280
  payment = { amount: 0, method: "check", depositDate: new Date().toISOString().slice(0, 10) };
1249
1281
  review = { reason: "", payerClaimControlNumber: "", disputedAmount: 0 };
1250
1282
  reportStatusOptions = REPORT_BILL_STATUS_OPTIONS;
1283
+ report = { status: null, company: "", representativeName: "", representativeRole: "", phone: "", callReference: "", note: "" };
1284
+ reportContactSummary = "";
1251
1285
  duplicateDelivery = null;
1252
1286
  duplicateDeliveryError = "";
1287
+ duplicateDraftInput = null;
1253
1288
  duplicate = { route: "ebill", faxNumber: "", email: "", mailingAddress: "" };
1254
- report = { status: null, company: "", representativeName: "", representativeRole: "", phone: "", callReference: "", note: "" };
1255
- reportContactSummary = "";
1256
1289
  correctionInitialBill = null;
1257
1290
  correctionAttachments = [];
1258
1291
  correctionAttentionFields = [];
@@ -1300,57 +1333,12 @@ class MindBillBillLifecycleComponent {
1300
1333
  else if (action === "close")
1301
1334
  this.panel = "close";
1302
1335
  else if (action === "send_duplicate")
1303
- this.beginSendDuplicate();
1336
+ this.prepareDuplicate(data);
1304
1337
  else if (action === "report_bill_status")
1305
1338
  this.beginReportStatus(data);
1306
1339
  else if (action === "view_eor" && data.eors[0])
1307
1340
  void this.openEor(data.eors[0].id, data.eors[0].filename);
1308
1341
  }
1309
- beginSendDuplicate() { this.panel = "duplicate"; this.loadDuplicateDelivery(); }
1310
- loadDuplicateDelivery() {
1311
- this.duplicateDeliveryError = "";
1312
- if (this.duplicateDelivery)
1313
- return;
1314
- this.store.getDeliveryOptions().then((delivery) => {
1315
- this.duplicateDelivery = delivery;
1316
- this.duplicate.route = delivery.recommended.route;
1317
- this.duplicate.faxNumber = delivery.contacts.faxNumber || "";
1318
- this.duplicate.email = delivery.contacts.claimsEmail || "";
1319
- this.duplicate.mailingAddress = delivery.contacts.mailingAddress || "";
1320
- }).catch((cause) => {
1321
- this.duplicateDeliveryError = cause instanceof Error ? cause.message : "Delivery options could not be loaded.";
1322
- });
1323
- }
1324
- duplicateRoutes() {
1325
- const seen = new Set();
1326
- return (this.duplicateDelivery?.options ?? []).filter((option) => {
1327
- if (seen.has(option.route))
1328
- return false;
1329
- seen.add(option.route);
1330
- return true;
1331
- });
1332
- }
1333
- duplicateReady() {
1334
- if (this.duplicate.route === "fax")
1335
- return this.duplicate.faxNumber.replace(/\D/g, "").length >= 10;
1336
- if (this.duplicate.route === "email")
1337
- return this.duplicate.email.includes("@");
1338
- if (this.duplicate.route === "mail")
1339
- return this.duplicate.mailingAddress.trim().length > 2;
1340
- return true;
1341
- }
1342
- async sendDuplicate() {
1343
- if (!this.duplicateDelivery || !this.duplicateReady())
1344
- return;
1345
- const route = this.duplicate.route;
1346
- const destination = route === "fax" ? { faxNumber: this.duplicate.faxNumber.trim() }
1347
- : route === "email" ? { email: this.duplicate.email.trim() }
1348
- : route === "mail" ? { mailingAddress: this.duplicate.mailingAddress.trim() }
1349
- : null;
1350
- await this.store.sendDuplicateBill({ route, ...(destination ? { destination } : {}) });
1351
- this.panel = "";
1352
- this.notice = "Duplicate bill sent.";
1353
- }
1354
1342
  beginReportStatus(data) {
1355
1343
  const contacts = reportBillStatusContacts(data.delivery);
1356
1344
  const parts = [];
@@ -1385,7 +1373,7 @@ class MindBillBillLifecycleComponent {
1385
1373
  async openAttachment(id, filename) { this.openBlob(await this.store.getAttachment(id), filename); }
1386
1374
  async openEor(id, filename) { this.openBlob(await this.store.getEor(id), filename); }
1387
1375
  async postPayment() { await this.store.postPayment(this.payment); this.panel = ""; this.notice = "Payment posted."; }
1388
- async submitReview() { await this.store.submitSecondReview({ ...this.review, disputedAmount: this.review.disputedAmount > 0 ? this.review.disputedAmount : undefined, attachmentIds: this.store.data()?.bill.attachments.map((document) => document.id) ?? [], route: "ebill" }); this.panel = ""; this.notice = "Second Review submitted."; }
1376
+ async submitReview() { await this.store.submitSecondReview({ ...this.review, ...(this.review.disputedAmount > 0 ? { disputedAmount: this.review.disputedAmount } : {}), attachmentIds: this.store.data()?.bill.attachments.map((document) => document.id) ?? [], route: "ebill" }); this.panel = ""; this.notice = "Second Review submitted."; }
1389
1377
  async closeBill() { if (!this.closeReason.trim())
1390
1378
  return; await this.store.closeBill({ reason: this.closeReason }); this.panel = ""; this.notice = "Bill closed."; }
1391
1379
  resubmitFromForm = async (input) => {
@@ -1397,6 +1385,66 @@ class MindBillBillLifecycleComponent {
1397
1385
  return { billId: data.bill.id, bill: { id: data.bill.id, state: data.lifecycle.state } };
1398
1386
  };
1399
1387
  finishCorrection() { this.panel = ""; this.correctionReason = ""; this.notice = "Corrected submission sent."; }
1388
+ duplicateFromForm = async (input) => {
1389
+ this.duplicateDraftInput = input;
1390
+ this.panel = "duplicate_route";
1391
+ await this.loadDuplicateDelivery();
1392
+ const billId = this.store.data()?.bill.id || this.billId;
1393
+ return { billId, bill: { id: billId, state: "draft" } };
1394
+ };
1395
+ finishDuplicate() { }
1396
+ async loadDuplicateDelivery() {
1397
+ this.duplicateDeliveryError = "";
1398
+ if (this.duplicateDelivery)
1399
+ return;
1400
+ try {
1401
+ const delivery = await this.store.getDeliveryOptions();
1402
+ this.duplicateDelivery = delivery;
1403
+ this.duplicate.route = delivery.recommended.route;
1404
+ this.duplicate.faxNumber = delivery.contacts.faxNumber || "";
1405
+ this.duplicate.email = delivery.contacts.claimsEmail || "";
1406
+ this.duplicate.mailingAddress = delivery.contacts.mailingAddress || "";
1407
+ }
1408
+ catch (cause) {
1409
+ this.duplicateDeliveryError = cause instanceof Error ? cause.message : "Delivery options could not be loaded.";
1410
+ }
1411
+ }
1412
+ duplicateRoutes() {
1413
+ const seen = new Set();
1414
+ return (this.duplicateDelivery?.options ?? []).filter((option) => {
1415
+ if (seen.has(option.route))
1416
+ return false;
1417
+ seen.add(option.route);
1418
+ return true;
1419
+ });
1420
+ }
1421
+ duplicateReady() {
1422
+ if (!this.duplicateDraftInput)
1423
+ return false;
1424
+ if (this.duplicate.route === "fax")
1425
+ return this.duplicate.faxNumber.replace(/\D/g, "").length >= 10;
1426
+ if (this.duplicate.route === "email")
1427
+ return this.duplicate.email.includes("@");
1428
+ if (this.duplicate.route === "mail")
1429
+ return this.duplicate.mailingAddress.trim().length > 2;
1430
+ return true;
1431
+ }
1432
+ async sendDuplicate() {
1433
+ if (!this.duplicateDelivery || !this.duplicateDraftInput || !this.duplicateReady())
1434
+ return;
1435
+ const route = this.duplicate.route;
1436
+ const destination = route === "fax" ? { faxNumber: this.duplicate.faxNumber.trim() }
1437
+ : route === "email" ? { email: this.duplicate.email.trim() }
1438
+ : route === "mail" ? { mailingAddress: this.duplicate.mailingAddress.trim() }
1439
+ : null;
1440
+ await this.store.sendDuplicateBill({
1441
+ bill: this.duplicateDraftInput.bill,
1442
+ ...(this.duplicateDraftInput.documents?.length ? { documents: this.duplicateDraftInput.documents } : {}),
1443
+ submission: { route, ...(destination ? { destination } : {}) },
1444
+ });
1445
+ this.panel = "";
1446
+ this.notice = "Duplicate bill sent.";
1447
+ }
1400
1448
  // "Submit New Bill" from a CLOSED bill: same prefilled submission form as the
1401
1449
  // correction flow, but the server keeps the closed bill closed and creates a
1402
1450
  // fresh original linked to it (both records chain in the submissions timeline).
@@ -1425,6 +1473,22 @@ class MindBillBillLifecycleComponent {
1425
1473
  this.correctionReason = "";
1426
1474
  this.panel = "resubmit";
1427
1475
  }
1476
+ prepareDuplicate(data) {
1477
+ this.correctionInitialBill = correctionBill(data);
1478
+ this.correctionAttachments = data.bill.attachments.map((attachment) => ({
1479
+ filename: attachment.filename,
1480
+ documentType: correctionDocumentType(attachment.documentType),
1481
+ ...(attachment.description ? { description: attachment.description } : {}),
1482
+ ...(attachment.reportType ? { reportTypeCode: attachment.reportType } : {}),
1483
+ loadBlob: () => this.store.getAttachment(attachment.id),
1484
+ ...(attachment.documentType === "w9" ? { locked: true, badge: "Auto-attached" } : {}),
1485
+ }));
1486
+ this.correctionAttentionFields = [];
1487
+ this.duplicateDraftInput = null;
1488
+ this.duplicateDelivery = null;
1489
+ this.duplicateDeliveryError = "";
1490
+ this.panel = "duplicate";
1491
+ }
1428
1492
  prepareNewBill(data) {
1429
1493
  this.correctionInitialBill = correctionBill(data);
1430
1494
  this.correctionAttachments = data.bill.attachments.map((attachment) => ({
@@ -1526,22 +1590,6 @@ class MindBillBillLifecycleComponent {
1526
1590
  @if (panel === 'payment') { <form class="card action-form" (submit)="$event.preventDefault(); postPayment()"><h3>Post payment</h3><label>Amount<input required type="number" min="0.01" step="0.01" [(ngModel)]="payment.amount" name="amount"></label><label>Method<select [(ngModel)]="payment.method" name="method"><option value="check">Check</option><option value="eft">EFT</option></select></label><label>Deposit date<input required type="date" [(ngModel)]="payment.depositDate" name="depositDate"></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Post payment</button></div></form> }
1527
1591
  @if (panel === 'review') { <form class="card action-form" (submit)="$event.preventDefault(); submitReview()"><h3>Submit Second Bill Review</h3><label>Reason<textarea required [(ngModel)]="review.reason" name="reason"></textarea></label><label>Payer claim control number<input required [(ngModel)]="review.payerClaimControlNumber" name="control"></label><label>Disputed amount<input type="number" min="0" step="0.01" [(ngModel)]="review.disputedAmount" name="disputed"></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Submit review</button></div></form> }
1528
1592
  @if (panel === 'close') { <form class="card action-form" (submit)="$event.preventDefault(); closeBill()"><h3>Close bill</h3><label>Reason<textarea required [(ngModel)]="closeReason" name="closeReason"></textarea></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Close bill</button></div></form> }
1529
- @if (panel === 'duplicate') {
1530
- <form class="card action-form" (submit)="$event.preventDefault(); sendDuplicate()">
1531
- <h3>Send duplicate bill</h3>
1532
- @if (!duplicateDelivery) {
1533
- <p class="muted">{{ duplicateDeliveryError || 'Loading delivery options…' }}</p>
1534
- <div><button type="button" (click)="panel=''">Cancel</button>@if (duplicateDeliveryError) { <button class="primary" type="button" (click)="loadDuplicateDelivery()">Try again</button> }</div>
1535
- } @else {
1536
- <p class="muted">Resend the unchanged submission packet to {{ duplicateDelivery.payerName }}.</p>
1537
- <label>Delivery method<select [(ngModel)]="duplicate.route" name="duplicateRoute">@for (option of duplicateRoutes(); track option.route) { <option [ngValue]="option.route">{{ option.label }}</option> }</select></label>
1538
- @if (duplicate.route === 'fax') { <label>Fax number<input required [(ngModel)]="duplicate.faxNumber" name="duplicateFax" placeholder="(000) 000-0000"></label> }
1539
- @if (duplicate.route === 'email') { <label>Email<input required type="email" [(ngModel)]="duplicate.email" name="duplicateEmail" placeholder="claims@payer.example"></label> }
1540
- @if (duplicate.route === 'mail') { <label>Mailing address<textarea required [(ngModel)]="duplicate.mailingAddress" name="duplicateMail"></textarea></label> }
1541
- <div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit" [disabled]="store.mutating() || !duplicateReady()">Send duplicate</button></div>
1542
- }
1543
- </form>
1544
- }
1545
1593
  @if (panel === 'report_status') {
1546
1594
  <form class="card action-form" (submit)="$event.preventDefault(); reportStatus()">
1547
1595
  <h3>Report Bill Status</h3>
@@ -1587,6 +1635,43 @@ class MindBillBillLifecycleComponent {
1587
1635
  </section>
1588
1636
  </div>
1589
1637
  }
1638
+ @if (panel === 'duplicate' && correctionInitialBill) {
1639
+ <div class="correction-backdrop" (mousedown)="closeCorrectionBackdrop($event)">
1640
+ <section class="correction-dialog" role="dialog" aria-modal="true" aria-label="Send duplicate bill">
1641
+ <button type="button" class="dialog-close" aria-label="Close" (click)="panel=''">×</button>
1642
+ <header><h2>Send duplicate bill</h2><p>The original submission remains immutable. Review or edit this fresh bill before choosing its delivery route and confirming transmission.</p></header>
1643
+ <mindbill-bill-submission
1644
+ [initialBill]="correctionInitialBill"
1645
+ [attachments]="correctionAttachments"
1646
+ [appearance]="appearance"
1647
+ [sessionEndpoint]="sessionEndpoint"
1648
+ [getSession]="getSession"
1649
+ [apiBaseUrl]="apiBaseUrl"
1650
+ [submitter]="duplicateFromForm"
1651
+ heading="Duplicate bill information"
1652
+ description="Review every field. The final step confirms the payer delivery route before the duplicate is sent."
1653
+ submitLabel="Continue to delivery"
1654
+ (submitted)="finishDuplicate()"
1655
+ />
1656
+ </section>
1657
+ </div>
1658
+ }
1659
+ @if (panel === 'duplicate_route') {
1660
+ <form class="card action-form" (submit)="$event.preventDefault(); sendDuplicate()">
1661
+ <h3>Confirm duplicate bill delivery</h3>
1662
+ @if (!duplicateDelivery) {
1663
+ <p class="muted">{{ duplicateDeliveryError || 'Loading delivery options…' }}</p>
1664
+ <div><button type="button" (click)="panel='duplicate'">Back</button>@if (duplicateDeliveryError) { <button class="primary" type="button" (click)="loadDuplicateDelivery()">Try again</button> }</div>
1665
+ } @else {
1666
+ <p class="muted">Confirm how this edited duplicate will be delivered to {{ duplicateDelivery.payerName }}.</p>
1667
+ <label>Delivery method<select [(ngModel)]="duplicate.route" name="duplicateRoute">@for (option of duplicateRoutes(); track option.route) { <option [ngValue]="option.route">{{ option.label }}</option> }</select></label>
1668
+ @if (duplicate.route === 'fax') { <label>Fax number<input required [(ngModel)]="duplicate.faxNumber" name="duplicateFax" placeholder="(000) 000-0000"></label> }
1669
+ @if (duplicate.route === 'email') { <label>Email<input required type="email" [(ngModel)]="duplicate.email" name="duplicateEmail" placeholder="claims@payer.example"></label> }
1670
+ @if (duplicate.route === 'mail') { <label>Mailing address<textarea required [(ngModel)]="duplicate.mailingAddress" name="duplicateMail"></textarea></label> }
1671
+ <div><button type="button" (click)="panel='duplicate'">Back</button><button class="primary" type="submit" [disabled]="store.mutating() || !duplicateReady()">Send duplicate</button></div>
1672
+ }
1673
+ </form>
1674
+ }
1590
1675
  @if (panel === 'submit_new_bill' && correctionInitialBill) {
1591
1676
  <div class="correction-backdrop" (mousedown)="closeCorrectionBackdrop($event)">
1592
1677
  <section class="correction-dialog" role="dialog" aria-modal="true" aria-label="Submit New Bill">
@@ -1699,22 +1784,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1699
1784
  @if (panel === 'payment') { <form class="card action-form" (submit)="$event.preventDefault(); postPayment()"><h3>Post payment</h3><label>Amount<input required type="number" min="0.01" step="0.01" [(ngModel)]="payment.amount" name="amount"></label><label>Method<select [(ngModel)]="payment.method" name="method"><option value="check">Check</option><option value="eft">EFT</option></select></label><label>Deposit date<input required type="date" [(ngModel)]="payment.depositDate" name="depositDate"></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Post payment</button></div></form> }
1700
1785
  @if (panel === 'review') { <form class="card action-form" (submit)="$event.preventDefault(); submitReview()"><h3>Submit Second Bill Review</h3><label>Reason<textarea required [(ngModel)]="review.reason" name="reason"></textarea></label><label>Payer claim control number<input required [(ngModel)]="review.payerClaimControlNumber" name="control"></label><label>Disputed amount<input type="number" min="0" step="0.01" [(ngModel)]="review.disputedAmount" name="disputed"></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Submit review</button></div></form> }
1701
1786
  @if (panel === 'close') { <form class="card action-form" (submit)="$event.preventDefault(); closeBill()"><h3>Close bill</h3><label>Reason<textarea required [(ngModel)]="closeReason" name="closeReason"></textarea></label><div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit">Close bill</button></div></form> }
1702
- @if (panel === 'duplicate') {
1703
- <form class="card action-form" (submit)="$event.preventDefault(); sendDuplicate()">
1704
- <h3>Send duplicate bill</h3>
1705
- @if (!duplicateDelivery) {
1706
- <p class="muted">{{ duplicateDeliveryError || 'Loading delivery options…' }}</p>
1707
- <div><button type="button" (click)="panel=''">Cancel</button>@if (duplicateDeliveryError) { <button class="primary" type="button" (click)="loadDuplicateDelivery()">Try again</button> }</div>
1708
- } @else {
1709
- <p class="muted">Resend the unchanged submission packet to {{ duplicateDelivery.payerName }}.</p>
1710
- <label>Delivery method<select [(ngModel)]="duplicate.route" name="duplicateRoute">@for (option of duplicateRoutes(); track option.route) { <option [ngValue]="option.route">{{ option.label }}</option> }</select></label>
1711
- @if (duplicate.route === 'fax') { <label>Fax number<input required [(ngModel)]="duplicate.faxNumber" name="duplicateFax" placeholder="(000) 000-0000"></label> }
1712
- @if (duplicate.route === 'email') { <label>Email<input required type="email" [(ngModel)]="duplicate.email" name="duplicateEmail" placeholder="claims@payer.example"></label> }
1713
- @if (duplicate.route === 'mail') { <label>Mailing address<textarea required [(ngModel)]="duplicate.mailingAddress" name="duplicateMail"></textarea></label> }
1714
- <div><button type="button" (click)="panel=''">Cancel</button><button class="primary" type="submit" [disabled]="store.mutating() || !duplicateReady()">Send duplicate</button></div>
1715
- }
1716
- </form>
1717
- }
1718
1787
  @if (panel === 'report_status') {
1719
1788
  <form class="card action-form" (submit)="$event.preventDefault(); reportStatus()">
1720
1789
  <h3>Report Bill Status</h3>
@@ -1760,6 +1829,43 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
1760
1829
  </section>
1761
1830
  </div>
1762
1831
  }
1832
+ @if (panel === 'duplicate' && correctionInitialBill) {
1833
+ <div class="correction-backdrop" (mousedown)="closeCorrectionBackdrop($event)">
1834
+ <section class="correction-dialog" role="dialog" aria-modal="true" aria-label="Send duplicate bill">
1835
+ <button type="button" class="dialog-close" aria-label="Close" (click)="panel=''">×</button>
1836
+ <header><h2>Send duplicate bill</h2><p>The original submission remains immutable. Review or edit this fresh bill before choosing its delivery route and confirming transmission.</p></header>
1837
+ <mindbill-bill-submission
1838
+ [initialBill]="correctionInitialBill"
1839
+ [attachments]="correctionAttachments"
1840
+ [appearance]="appearance"
1841
+ [sessionEndpoint]="sessionEndpoint"
1842
+ [getSession]="getSession"
1843
+ [apiBaseUrl]="apiBaseUrl"
1844
+ [submitter]="duplicateFromForm"
1845
+ heading="Duplicate bill information"
1846
+ description="Review every field. The final step confirms the payer delivery route before the duplicate is sent."
1847
+ submitLabel="Continue to delivery"
1848
+ (submitted)="finishDuplicate()"
1849
+ />
1850
+ </section>
1851
+ </div>
1852
+ }
1853
+ @if (panel === 'duplicate_route') {
1854
+ <form class="card action-form" (submit)="$event.preventDefault(); sendDuplicate()">
1855
+ <h3>Confirm duplicate bill delivery</h3>
1856
+ @if (!duplicateDelivery) {
1857
+ <p class="muted">{{ duplicateDeliveryError || 'Loading delivery options…' }}</p>
1858
+ <div><button type="button" (click)="panel='duplicate'">Back</button>@if (duplicateDeliveryError) { <button class="primary" type="button" (click)="loadDuplicateDelivery()">Try again</button> }</div>
1859
+ } @else {
1860
+ <p class="muted">Confirm how this edited duplicate will be delivered to {{ duplicateDelivery.payerName }}.</p>
1861
+ <label>Delivery method<select [(ngModel)]="duplicate.route" name="duplicateRoute">@for (option of duplicateRoutes(); track option.route) { <option [ngValue]="option.route">{{ option.label }}</option> }</select></label>
1862
+ @if (duplicate.route === 'fax') { <label>Fax number<input required [(ngModel)]="duplicate.faxNumber" name="duplicateFax" placeholder="(000) 000-0000"></label> }
1863
+ @if (duplicate.route === 'email') { <label>Email<input required type="email" [(ngModel)]="duplicate.email" name="duplicateEmail" placeholder="claims@payer.example"></label> }
1864
+ @if (duplicate.route === 'mail') { <label>Mailing address<textarea required [(ngModel)]="duplicate.mailingAddress" name="duplicateMail"></textarea></label> }
1865
+ <div><button type="button" (click)="panel='duplicate'">Back</button><button class="primary" type="submit" [disabled]="store.mutating() || !duplicateReady()">Send duplicate</button></div>
1866
+ }
1867
+ </form>
1868
+ }
1763
1869
  @if (panel === 'submit_new_bill' && correctionInitialBill) {
1764
1870
  <div class="correction-backdrop" (mousedown)="closeCorrectionBackdrop($event)">
1765
1871
  <section class="correction-dialog" role="dialog" aria-modal="true" aria-label="Submit New Bill">
@@ -1826,8 +1932,9 @@ function correctionBill(data) {
1826
1932
  claimsAdministrator: { id: data.injury.claimsAdminId || "", name: data.injury.claimsAdminName || "" },
1827
1933
  },
1828
1934
  service: { date: data.bill.dos, ...(data.bill.dosEnd !== undefined ? { endDate: data.bill.dosEnd } : {}), ...(data.bill.authorizationNumber !== undefined ? { authorizationNumber: data.bill.authorizationNumber } : {}) },
1829
- billingProvider: {
1935
+ billingProvider: billing?.taxIdType === 'SSN' && billing.taxIdConfigured ? { sourceBillId: data.bill.id } : {
1830
1936
  name: billing?.name || "", taxId: billing?.taxId || "", npi: billing?.npi || "", phone: billing?.phone || "",
1937
+ ...(billing?.taxIdType ? { taxIdType: billing.taxIdType } : {}),
1831
1938
  address: { line1: billing?.billingStreet || "", city: billing?.billingCity || "", state: billing?.billingState || "", postalCode: billing?.billingZip || "" },
1832
1939
  },
1833
1940
  renderingProvider: {
@@ -2560,7 +2667,7 @@ class MindBillOrganizationOnboardingComponent {
2560
2667
  step = "practice";
2561
2668
  saving = false;
2562
2669
  saved = {};
2563
- identity = { name: "", legalName: "", taxId: "", npi: "", phone: "", email: "" };
2670
+ identity = { name: "", legalName: "", taxId: "", taxIdType: "EIN", npi: "", phone: "", email: "" };
2564
2671
  provider = { name: "", taxId: "", npi: "", billType: "Professional", phone: "", billingStreet: "", billingCity: "", billingState: "", billingZip: "" };
2565
2672
  locations = [{ name: "", street: "", city: "", state: "", zip: "", isPrimary: false }];
2566
2673
  w9File = null;
@@ -2595,12 +2702,15 @@ class MindBillOrganizationOnboardingComponent {
2595
2702
  adoptProfile(profile) {
2596
2703
  this.profile = profile;
2597
2704
  this.identity = {
2598
- name: profile.practiceIdentity.name ?? this.identity.name,
2599
- legalName: profile.practiceIdentity.legalName ?? this.identity.legalName,
2600
- taxId: profile.practiceIdentity.taxId ?? this.identity.taxId,
2601
- npi: profile.practiceIdentity.npi ?? this.identity.npi,
2602
- phone: profile.practiceIdentity.phone ?? this.identity.phone,
2603
- 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 ?? '',
2604
2714
  };
2605
2715
  if (profile.billingProviders[0])
2606
2716
  this.provider = { billType: "Professional", ...profile.billingProviders[0] };
@@ -2647,12 +2757,23 @@ class MindBillOrganizationOnboardingComponent {
2647
2757
  }
2648
2758
  savePractice() {
2649
2759
  void this.run(() => this.client.saveBillingProfile({
2650
- practiceIdentity: this.identity,
2651
- ...(this.provider.name.trim() || this.provider.taxId.trim() || this.provider.npi.trim()
2652
- ? { 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)] }
2653
2763
  : {}),
2654
2764
  }), "practice");
2655
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
+ }
2656
2777
  saveLocations() {
2657
2778
  void this.run(() => this.client.saveLocations(this.locations.filter((item) => item.name.trim() || item.street.trim())), "locations");
2658
2779
  }
@@ -2682,7 +2803,10 @@ class MindBillOrganizationOnboardingComponent {
2682
2803
  <div class="grid">
2683
2804
  <label>Practice name<input [(ngModel)]="identity.name" [disabled]="saving"></label>
2684
2805
  <label>Legal name<input [(ngModel)]="identity.legalName" [disabled]="saving"></label>
2685
- <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>
2686
2810
  <label>Group NPI<input [(ngModel)]="identity.npi" [disabled]="saving"></label>
2687
2811
  <label>Phone<input [(ngModel)]="identity.phone" [disabled]="saving"></label>
2688
2812
  <label>Email<input [(ngModel)]="identity.email" [disabled]="saving"></label>
@@ -2690,7 +2814,10 @@ class MindBillOrganizationOnboardingComponent {
2690
2814
  <h3>Billing provider (pay-to)</h3>
2691
2815
  <div class="grid">
2692
2816
  <label>Billing provider name<input [(ngModel)]="provider.name" [disabled]="saving"></label>
2693
- <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>
2694
2821
  <label>Billing NPI<input [(ngModel)]="provider.npi" [disabled]="saving"></label>
2695
2822
  <label>Billing phone<input [(ngModel)]="provider.phone" [disabled]="saving"></label>
2696
2823
  <label class="span">Street<input [(ngModel)]="provider.billingStreet" [disabled]="saving"></label>
@@ -2745,7 +2872,7 @@ class MindBillOrganizationOnboardingComponent {
2745
2872
  @if (errorMessage) { <div class="error" role="alert">{{ errorMessage }}</div> }
2746
2873
  </div>
2747
2874
  </section>
2748
- `, 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"] }] });
2749
2876
  }
2750
2877
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImport: i0, type: MindBillOrganizationOnboardingComponent, decorators: [{
2751
2878
  type: Component,
@@ -2767,7 +2894,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
2767
2894
  <div class="grid">
2768
2895
  <label>Practice name<input [(ngModel)]="identity.name" [disabled]="saving"></label>
2769
2896
  <label>Legal name<input [(ngModel)]="identity.legalName" [disabled]="saving"></label>
2770
- <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>
2771
2901
  <label>Group NPI<input [(ngModel)]="identity.npi" [disabled]="saving"></label>
2772
2902
  <label>Phone<input [(ngModel)]="identity.phone" [disabled]="saving"></label>
2773
2903
  <label>Email<input [(ngModel)]="identity.email" [disabled]="saving"></label>
@@ -2775,7 +2905,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
2775
2905
  <h3>Billing provider (pay-to)</h3>
2776
2906
  <div class="grid">
2777
2907
  <label>Billing provider name<input [(ngModel)]="provider.name" [disabled]="saving"></label>
2778
- <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>
2779
2912
  <label>Billing NPI<input [(ngModel)]="provider.npi" [disabled]="saving"></label>
2780
2913
  <label>Billing phone<input [(ngModel)]="provider.phone" [disabled]="saving"></label>
2781
2914
  <label class="span">Street<input [(ngModel)]="provider.billingStreet" [disabled]="saving"></label>
@@ -2830,7 +2963,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.22", ngImpo
2830
2963
  @if (errorMessage) { <div class="error" role="alert">{{ errorMessage }}</div> }
2831
2964
  </div>
2832
2965
  </section>
2833
- `, 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"] }]
2834
2967
  }], propDecorators: { appearance: [{
2835
2968
  type: Input
2836
2969
  }], sessionEndpoint: [{