feat: payment PDF extraction, import, and remittance tracking
- Add Upload Payment Documents section with Extract & Download (Excel) and Extract & Import (database) buttons - PDF extractor (pdfplumber) parses MassHealth RA PDFs: two-pass strategy joins summary-page ICN/patient map with detail-page procedure data (CDT code, paid code, tooth, date, allowed amount) - RA cover-page summary (Payee ID, RA #, Payment Amount, etc.) included as separate Excel sheet; numeric values written as numbers - Backend PDF import route groups rows by Member #, finds/creates patient, creates Payment + ServiceLines with ICN per procedure - Add icn, paidCode, allowedAmount fields to ServiceLine schema - Payments table: status simplified to Paid in Full / Balance; adjustment auto-computed on mhPaidAmount/copayment change; Paid in Full and Revert buttons with confirmation dialogs - Edit Payment modal: shows ICN, Paid Code, Allowed Amount per line - PDF Import badge distinguishes from OCR imports in payments table Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -442,12 +442,19 @@ router.patch(
|
||||
return res.status(400).json({ message: "Invalid mhPaidAmount value" });
|
||||
}
|
||||
|
||||
const existing = await prisma.payment.findUnique({ where: { id: paymentId } });
|
||||
if (!existing) return res.status(404).json({ message: "Payment not found" });
|
||||
|
||||
const totalBilled = Number(existing.totalBilled);
|
||||
const copayment = Number(existing.copayment ?? 0);
|
||||
const adjustment = Math.max(0, totalBilled - mhPaidAmount - copayment);
|
||||
|
||||
const updated = await prisma.payment.update({
|
||||
where: { id: paymentId },
|
||||
data: { mhPaidAmount, updatedById: userId },
|
||||
data: { mhPaidAmount, adjustment, updatedById: userId },
|
||||
});
|
||||
|
||||
return res.json({ ...updated, mhPaidAmount: Number(updated.mhPaidAmount) });
|
||||
return res.json({ ...updated, mhPaidAmount: Number(updated.mhPaidAmount), adjustment: Number(updated.adjustment) });
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Failed to update MH paid amount";
|
||||
return res.status(500).json({ message });
|
||||
@@ -469,12 +476,19 @@ router.patch(
|
||||
return res.status(400).json({ message: "Invalid copayment value" });
|
||||
}
|
||||
|
||||
const existing = await prisma.payment.findUnique({ where: { id: paymentId } });
|
||||
if (!existing) return res.status(404).json({ message: "Payment not found" });
|
||||
|
||||
const totalBilled = Number(existing.totalBilled);
|
||||
const mhPaidAmount = Number(existing.mhPaidAmount ?? 0);
|
||||
const adjustment = Math.max(0, totalBilled - mhPaidAmount - val);
|
||||
|
||||
const updated = await prisma.payment.update({
|
||||
where: { id: paymentId },
|
||||
data: { copayment: val, updatedById: userId },
|
||||
data: { copayment: val, adjustment, updatedById: userId },
|
||||
});
|
||||
|
||||
return res.json({ ...updated, copayment: Number(updated.copayment) });
|
||||
return res.json({ ...updated, copayment: Number(updated.copayment), adjustment: Number(updated.adjustment) });
|
||||
} catch (err: unknown) {
|
||||
const message = err instanceof Error ? err.message : "Failed to update copayment";
|
||||
return res.status(500).json({ message });
|
||||
|
||||
Reference in New Issue
Block a user