feat: MassHealth PDF import auto-pays full balance + patient name fix

- PDF import now marks payments as PAID when MassHealth patient's
  mhPaidAmount >= totalBilled (no patient balance)
- Newly created patients from MH vouchers get insuranceProvider = 'MassHealth'
- Existing patients with blank insuranceProvider get it filled on import
- Fix: update patient name from PDF if existing record has empty name
- Various frontend/selenium/route updates

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-26 00:16:31 -04:00
co-authored by Claude Sonnet 4.6
parent 9efe5c8469
commit b7e06adf2f
15 changed files with 611 additions and 448 deletions
+26 -8
View File
@@ -261,27 +261,44 @@ export const pdfImportService = {
data: {
firstName,
lastName,
insuranceId: memberNo || null,
insuranceId: memberNo || null,
insuranceProvider: "MassHealth",
dateOfBirth: new Date(Date.UTC(1900, 0, 1)),
gender: "",
phone: "",
userId,
},
});
} else {
const updates: Record<string, string> = {};
if (patientName && !patient.firstName && !patient.lastName) {
const { firstName, lastName } = parsePdfName(patientName);
updates.firstName = firstName;
updates.lastName = lastName;
}
if (!patient.insuranceProvider) {
updates.insuranceProvider = "MassHealth";
}
if (Object.keys(updates).length > 0) {
patient = await tx.patient.update({ where: { id: patient.id }, data: updates });
}
}
const isMassHealth = patient.insuranceProvider?.startsWith("MassHealth") ?? false;
const paidInFull = isMassHealth && totalMhPaid.gte(totalBilled);
// 2. Create payment
const payment = await tx.payment.create({
data: {
patientId: patient.id,
patientId: patient.id,
userId,
totalBilled,
totalPaid: new Decimal(0),
totalPaid: paidInFull ? totalMhPaid : new Decimal(0),
totalAdjusted: new Decimal(0),
totalDue: totalBilled,
mhPaidAmount: totalMhPaid,
totalDue: paidInFull ? new Decimal(0) : totalBilled,
mhPaidAmount: totalMhPaid,
adjustment,
status: "PENDING",
status: paidInFull ? "PAID" : "PENDING",
notes: `PDF import from ${first["Source File"] ?? "unknown file"}`,
},
});
@@ -290,7 +307,8 @@ export const pdfImportService = {
for (const row of patientRows) {
const billed = new Decimal(row["Submitted Amount"] || 0);
const mhPaid = new Decimal(row["Paid Amount"] || 0);
const due = Decimal.max(0, billed.minus(mhPaid));
const linePaidInFull = isMassHealth && mhPaid.gte(billed);
const due = linePaidInFull ? new Decimal(0) : Decimal.max(0, billed.minus(mhPaid));
const { toothNumber, toothSurface } = parseTooth(row["Tooth"]);
const allowed = new Decimal(row["Allowed Amount"] || 0);
@@ -309,7 +327,7 @@ export const pdfImportService = {
totalPaid: mhPaid,
totalAdjusted: new Decimal(0),
totalDue: due,
status: mhPaid.gt(0) ? "PARTIALLY_PAID" : "UNPAID",
status: linePaidInFull ? "PAID" : mhPaid.gt(0) ? "PARTIALLY_PAID" : "UNPAID",
},
});
}