feat: MassHealth member detail demographics, wait for name/plan before PDF
- Extract gender, address (street/city/state/zip) and home phone from the MassHealth Member Detail page and save to the patient; phone is only filled when the patient has none - Shared extract_eligibility_row polls up to 30s until the matching results row has both name and plan before the PDF is printed (AngularJS fills cell text after the rows appear); used by all three MH eligibility workers - Fall back to the Member Detail heading for the name when the results table never filled it in Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -60,6 +60,33 @@ export function splitName(fullName?: string | null) {
|
||||
return { firstName, lastName };
|
||||
}
|
||||
|
||||
/**
|
||||
* Patient updates from the MassHealth Member Detail block (gender, address,
|
||||
* home phone) — only fields the portal actually returned. Phone is only
|
||||
* filled when the patient has none, so a number the office entered is kept.
|
||||
*/
|
||||
export function memberDetailDemographics(
|
||||
seleniumResult: any,
|
||||
existingPhone?: string | null
|
||||
): Record<string, string> {
|
||||
const updates: Record<string, string> = {};
|
||||
for (const key of ["address", "city", "state", "zipCode"] as const) {
|
||||
const val = seleniumResult?.[key];
|
||||
if (typeof val === "string" && val.trim()) updates[key] = val.trim();
|
||||
}
|
||||
|
||||
// "Female"/"Male" → patient form values
|
||||
const rawGender = String(seleniumResult?.gender ?? "").trim().toUpperCase();
|
||||
const gender = rawGender.startsWith("M") ? "male" : rawGender.startsWith("F") ? "female" : "";
|
||||
if (gender) updates.gender = gender;
|
||||
|
||||
// Stored like the patient form: "1" + 10 digits
|
||||
const digits = String(seleniumResult?.phone ?? "").replace(/\D/g, "");
|
||||
if (digits.length === 10 && !(existingPhone ?? "").trim()) updates.phone = "1" + digits;
|
||||
|
||||
return updates;
|
||||
}
|
||||
|
||||
export async function imageToPdfBuffer(imagePath: string): Promise<Buffer> {
|
||||
return new Promise<Buffer>((resolve, reject) => {
|
||||
try {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
callPythonSync,
|
||||
splitName,
|
||||
createOrUpdatePatientByInsuranceId,
|
||||
memberDetailDemographics,
|
||||
} from "./_shared";
|
||||
|
||||
export interface CmspEligibilityHistoryRemainingProcessorInput {
|
||||
@@ -112,6 +113,7 @@ export async function runCmspEligibilityHistoryRemainingProcessor(
|
||||
const updates: any = {};
|
||||
if (newStatus) updates.status = newStatus;
|
||||
if (seleniumInsurance) updates.insuranceProvider = seleniumInsurance;
|
||||
Object.assign(updates, memberDetailDemographics(seleniumResult, patient.phone));
|
||||
|
||||
const remainingBenefit = seleniumResult.remaining_amount?.trim() || null;
|
||||
if (remainingBenefit) updates.remainingBenefit = remainingBenefit;
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
callPythonSync,
|
||||
splitName,
|
||||
createOrUpdatePatientByInsuranceId,
|
||||
memberDetailDemographics,
|
||||
} from "./_shared";
|
||||
|
||||
export interface EligibilityHistoryProcessorInput {
|
||||
@@ -103,6 +104,7 @@ export async function runEligibilityHistoryProcessor(
|
||||
|
||||
const updates: any = { status: newStatus };
|
||||
if (seleniumInsurance) updates.insuranceProvider = seleniumInsurance;
|
||||
Object.assign(updates, memberDetailDemographics(seleniumResult, patient.phone));
|
||||
await storage.updatePatient(patient.id, updates);
|
||||
outputResult.patientUpdateStatus = `Patient status updated to ${newStatus}`;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user