@mindbill/react 0.77.63 → 0.77.64

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/dist/index.d.ts CHANGED
@@ -439,6 +439,11 @@ type BillSubmissionFormProps = {
439
439
  procedureOptions?: BillSubmissionProcedureOption[];
440
440
  /** Extend the existing procedure picker with treatment codes and authoritative fee quotes. */
441
441
  treatmentBilling?: boolean;
442
+ /** Lines added when a procedure is chosen, keyed by that procedure's code. A code already on the bill is not added again. */
443
+ companionLines?: Readonly<Record<string, readonly {
444
+ code: string;
445
+ units?: number;
446
+ }[]>>;
442
447
  /** Opt in to editable treatment billed charges; fee quotes remain separate estimates. */
443
448
  editableTreatmentCharges?: boolean;
444
449
  onSearchProcedureCodes?: (input?: BillProcedureCodeSearchInput) => Promise<BillProcedureCodePage>;
@@ -524,7 +529,7 @@ declare function BillSubmissionProvidersSection(): ReactElement;
524
529
  declare function BillSubmissionServiceLinesSection(): ReactElement;
525
530
  declare function BillSubmissionAttachmentsSection(): ReactElement;
526
531
  declare function BillSubmissionActions(): ReactElement;
527
- declare function BillSubmissionForm({ initialBill, idempotencyKey, attachments, onSubmit, onSubmitted, getSession, sessionEndpoint, apiBaseUrl, profileOptions, billingSettings, reportAutofill, profileDisplay, fetch: fetchOverride, onListMedicalProviderNetworks, onListClaimsAdministrators, onSearchClaimsAdministrators, onGetClaimsAdministratorDirectory, claimsAdministratorSources, claimsAdministratorHint, diagnosisOptions, onSearchDiagnoses, onLookupPostalCode, procedureOptions, treatmentBilling, editableTreatmentCharges, onSearchProcedureCodes, onQuoteFee, modifierOptions, taxonomyOptions, deliveryRoutePicker, deliveryRouteDialogTitle, attachmentReportTypeMode, attachmentReportTypes, defaultAttachmentReportType, appearance, className, style, disabled, submitLabel, heading, description, attentionFields, attentionMessage, children, }: BillSubmissionFormProps): ReactElement;
532
+ declare function BillSubmissionForm({ initialBill, idempotencyKey, attachments, onSubmit, onSubmitted, getSession, sessionEndpoint, apiBaseUrl, profileOptions, billingSettings, reportAutofill, profileDisplay, fetch: fetchOverride, onListMedicalProviderNetworks, onListClaimsAdministrators, onSearchClaimsAdministrators, onGetClaimsAdministratorDirectory, claimsAdministratorSources, claimsAdministratorHint, diagnosisOptions, onSearchDiagnoses, onLookupPostalCode, procedureOptions, treatmentBilling, companionLines, editableTreatmentCharges, onSearchProcedureCodes, onQuoteFee, modifierOptions, taxonomyOptions, deliveryRoutePicker, deliveryRouteDialogTitle, attachmentReportTypeMode, attachmentReportTypes, defaultAttachmentReportType, appearance, className, style, disabled, submitLabel, heading, description, attentionFields, attentionMessage, children, }: BillSubmissionFormProps): ReactElement;
528
533
 
529
534
  type BillSubmissionProfileOption<K extends "billingProvider" | "renderingProvider" | "serviceLocation"> = {
530
535
  id: string;
package/dist/index.js CHANGED
@@ -8220,6 +8220,7 @@ function billSubmissionCalculationContext(code, placeOfService, details, saved =
8220
8220
  return context;
8221
8221
  }
8222
8222
  var isMedicalLegalCode = (code) => /^ML/i.test(code.trim());
8223
+ var billingModeForLines = (lines) => lines.some((line) => isMedicalLegalCode(line.code)) ? "med_legal" : "professional";
8223
8224
  function billSubmissionFeeRequest(bill, line, context = line.feeContext ?? {}) {
8224
8225
  const dateOfService = parseBillSubmissionDate(line.serviceDate ?? bill.service.date) ?? "";
8225
8226
  const sameDayServices = bill.serviceLines.filter((candidate) => candidate.code.trim() && parseBillSubmissionDate(candidate.serviceDate ?? bill.service.date) === dateOfService);
@@ -8383,6 +8384,19 @@ function blankLine() {
8383
8384
  function lineHasContent(line) {
8384
8385
  return Boolean(line.code.trim() || line.modifiers?.length || line.charge != null || line.drug || line.formData);
8385
8386
  }
8387
+ function withAddedBillSubmissionLines(lines, added) {
8388
+ if (!added?.length) return lines;
8389
+ const entered = [...lines];
8390
+ while (entered.length && !lineHasContent(entered.at(-1))) entered.pop();
8391
+ const present = new Set(entered.map((line) => line.code.trim().toUpperCase()));
8392
+ for (const line of added) {
8393
+ const code = line.code.trim().toUpperCase();
8394
+ if (!code || present.has(code)) continue;
8395
+ present.add(code);
8396
+ entered.push({ code, modifiers: [], units: line.units ?? 1 });
8397
+ }
8398
+ return entered;
8399
+ }
8386
8400
  function ensureTrailingBillSubmissionLine(lines) {
8387
8401
  const normalized = lines.length ? lines.map((line) => ({ ...line, modifiers: [...line.modifiers ?? []], units: line.units ?? 1 })) : [];
8388
8402
  while (normalized.length > 1 && !lineHasContent(normalized.at(-1)) && !lineHasContent(normalized.at(-2))) normalized.pop();
@@ -8492,7 +8506,7 @@ function setBillSubmissionLineDiagnoses(bill, index, codes2) {
8492
8506
  }
8493
8507
  function cloneInitialBill(bill, treatmentBilling = false) {
8494
8508
  const cloned = cloneBill(bill);
8495
- if (treatmentBilling && cloned.serviceLines.some((line) => line.code.trim() && !isMedicalLegalCode(line.code))) cloned.billingMode = "professional";
8509
+ if (treatmentBilling && cloned.serviceLines.some((line) => line.code.trim())) cloned.billingMode = billingModeForLines(cloned.serviceLines);
8496
8510
  if (cloned.billingMode !== "professional") cloned.diagnoses = applyBillSubmissionEvaluationDiagnoses(cloned.diagnoses, initialEvaluationType(bill));
8497
8511
  return billSubmissionUsesSharedDiagnoses(cloned) ? setBillSubmissionSharedDiagnoses(cloned, cloned.diagnoses ?? []) : cloned;
8498
8512
  }
@@ -8581,14 +8595,13 @@ function validateBillSubmission(bill) {
8581
8595
  if (bill.renderingProvider?.taxonomy && !/^[A-Za-z0-9]{10}$/.test(bill.renderingProvider.taxonomy.trim())) errors["renderingProvider.taxonomy"] = "Enter a valid 10-character taxonomy code.";
8582
8596
  if (bill.serviceLocation?.placeOfServiceCode && !/^\d{2}$/.test(bill.serviceLocation.placeOfServiceCode.trim())) errors["serviceLocation.placeOfServiceCode"] = "Enter a valid 2-digit place of service code.";
8583
8597
  const lines = submittedLines(bill.serviceLines);
8584
- if (lines.some((line) => isMedicalLegalCode(line.code)) && lines.some((line) => line.code && !isMedicalLegalCode(line.code))) errors.serviceLines = "Submit medical-legal and treatment services on separate bills.";
8585
8598
  if (!lines.length) errors.serviceLines = "Add at least one service line";
8586
8599
  lines.forEach((line, index) => {
8587
8600
  required2(`serviceLines.${index}.code`, line.code, "Select a procedure code.");
8588
8601
  const pointers = line.diagnosisPointers ?? [];
8589
8602
  if (pointers.length > 4 || new Set(pointers).size !== pointers.length || pointers.some((pointer) => !Number.isInteger(pointer) || pointer < 1 || pointer > (bill.diagnoses?.length ?? 0)) || bill.billingMode === "professional" && !pointers.length) errors[`serviceLines.${index}.diagnosisPointers`] = "Select up to four diagnoses for this service line.";
8590
8603
  if (!Number.isInteger(line.units) || (line.units ?? 0) < 1) errors[`serviceLines.${index}.units`] = "Enter at least 1 unit";
8591
- if (bill.billingMode === "professional" && (!Number.isFinite(line.charge) || (line.charge ?? 0) <= 0)) errors[`serviceLines.${index}.charge`] = "Enter the billed charge";
8604
+ if ((bill.billingMode === "professional" || !isMedicalLegalCode(line.code) && lines.some((other) => isMedicalLegalCode(other.code))) && (!Number.isFinite(line.charge) || (line.charge ?? 0) <= 0)) errors[`serviceLines.${index}.charge`] = "Enter the billed charge";
8592
8605
  });
8593
8606
  return { valid: Object.keys(errors).length === 0, fieldErrors: errors };
8594
8607
  }
@@ -8815,6 +8828,7 @@ function BillSubmissionForm({
8815
8828
  onLookupPostalCode,
8816
8829
  procedureOptions,
8817
8830
  treatmentBilling = false,
8831
+ companionLines,
8818
8832
  editableTreatmentCharges = false,
8819
8833
  onSearchProcedureCodes,
8820
8834
  onQuoteFee,
@@ -9036,7 +9050,8 @@ function BillSubmissionForm({
9036
9050
  if (Object.hasOwn(patch, "modifiers")) setFeeDetails((current) => ({ ...current, [index]: { ...detailsForLine(index), interpretationLocation: "", professionalComponentBasis: "" } }));
9037
9051
  if (Object.hasOwn(patch, "code")) setFeeDetails((current) => ({ ...current, [index]: {} }));
9038
9052
  setBill((current) => {
9039
- const serviceLines = ensureTrailingBillSubmissionLine(current.serviceLines.map((line, lineIndex) => {
9053
+ const added = patch.code != null && patch.code !== current.serviceLines[index]?.code ? Object.entries(companionLines ?? {}).find(([code]) => code.trim().toUpperCase() === patch.code.trim().toUpperCase())?.[1] : void 0;
9054
+ const serviceLines = ensureTrailingBillSubmissionLine(withAddedBillSubmissionLines(current.serviceLines.map((line, lineIndex) => {
9040
9055
  if (lineIndex !== index) return line;
9041
9056
  const next = { ...line, ...patch };
9042
9057
  if (patch.code != null && patch.code !== line.code) {
@@ -9056,9 +9071,9 @@ function BillSubmissionForm({
9056
9071
  if (charge != null) return { ...next, charge };
9057
9072
  if (Object.hasOwn(patch, "code")) delete next.charge;
9058
9073
  return next;
9059
- }));
9074
+ }), added));
9060
9075
  const populated = serviceLines.filter((line) => line.code.trim());
9061
- return { ...sharedDiagnoses ? setBillSubmissionSharedDiagnoses(replaceBillSubmissionServiceLines(current, serviceLines), current.diagnoses ?? []) : replaceBillSubmissionServiceLines(current, serviceLines), ...treatmentBilling && populated.length ? { billingMode: populated.every((line) => isMedicalLegalCode(line.code)) ? "med_legal" : "professional" } : {} };
9076
+ return { ...sharedDiagnoses ? setBillSubmissionSharedDiagnoses(replaceBillSubmissionServiceLines(current, serviceLines), current.diagnoses ?? []) : replaceBillSubmissionServiceLines(current, serviceLines), ...treatmentBilling && populated.length ? { billingMode: billingModeForLines(populated) } : {} };
9062
9077
  });
9063
9078
  };
9064
9079
  const setLineCharge = (index, charge) => setBill((current) => ({
@@ -9416,7 +9431,7 @@ function BillSubmissionForm({
9416
9431
  } else if (charge != null) next.charge = charge;
9417
9432
  return next;
9418
9433
  }).filter(lineHasContent);
9419
- const clean = { ...cloneBill(bill), serviceLines: pricedLines, ...treatmentBilling && pricedLines.length ? { billingMode: pricedLines.every((line) => isMedicalLegalCode(line.code)) ? "med_legal" : "professional" } : {} };
9434
+ const clean = { ...cloneBill(bill), serviceLines: pricedLines, ...treatmentBilling && pricedLines.length ? { billingMode: billingModeForLines(pricedLines) } : {} };
9420
9435
  const previewBillKey = JSON.stringify(clean);
9421
9436
  const previewCurrent = cmsPreview?.billKey === previewBillKey;
9422
9437
  const liveErrors = JSON.stringify(validateBillSubmission(clean).fieldErrors);
@@ -20067,7 +20082,7 @@ function ConnectedBillLifecycle({
20067
20082
  initialBill: correctionInitialBill,
20068
20083
  profileOptions: data.options ? organizationProfileOptions(data.options) : {},
20069
20084
  ...billingSettings ? { billingSettings } : {},
20070
- treatmentBilling: data.bill.billingMode === "professional",
20085
+ treatmentBilling: data.bill.billingMode === "professional" || data.bill.lineItems.some((line) => !/^ML/i.test(line.code.trim())),
20071
20086
  attachments: correctionAttachments,
20072
20087
  onSubmit: submitCorrection,
20073
20088
  onListMedicalProviderNetworks: lifecycle.listMedicalProviderNetworks,
@@ -20108,7 +20123,7 @@ function ConnectedBillLifecycle({
20108
20123
  initialBill: correctionInitialBill,
20109
20124
  profileOptions: data.options ? organizationProfileOptions(data.options) : {},
20110
20125
  ...billingSettings ? { billingSettings } : {},
20111
- treatmentBilling: data.bill.billingMode === "professional",
20126
+ treatmentBilling: data.bill.billingMode === "professional" || data.bill.lineItems.some((line) => !/^ML/i.test(line.code.trim())),
20112
20127
  attachments: correctionAttachments,
20113
20128
  onSubmit: submitNewBillFromForm,
20114
20129
  onListMedicalProviderNetworks: lifecycle.listMedicalProviderNetworks,
@@ -20232,7 +20247,7 @@ function ConnectedBillLifecycle({
20232
20247
  initialBill: correctionInitialBill,
20233
20248
  profileOptions: data.options ? organizationProfileOptions(data.options) : {},
20234
20249
  ...billingSettings ? { billingSettings } : {},
20235
- treatmentBilling: data.bill.billingMode === "professional",
20250
+ treatmentBilling: data.bill.billingMode === "professional" || data.bill.lineItems.some((line) => !/^ML/i.test(line.code.trim())),
20236
20251
  attachments: correctionAttachments,
20237
20252
  onSubmit: submitDuplicateFromForm,
20238
20253
  onListMedicalProviderNetworks: lifecycle.listMedicalProviderNetworks,