feat: add Check MH Payment automation and MH Paid column

- Add selenium_MHPaymentCheckWorker.py: logs into MassHealth portal, navigates to Search Claims, enters claim number, extracts totalPaidAmount from results table
- Register /mh-payment-check endpoint in Selenium agent
- Add mhPaidAmount field to Payment model with migration
- Add PATCH /api/payments/:id/mh-payment-check backend route: fetches MH credentials, calls selenium, stores result
- Add Claim No. column (MassHealth claim number) as first data column in payments table
- Move Payment ID and Claim ID columns to end of table
- Add MH Paid column showing mhPaidAmount in green
- Wire Check MH Payment button to call API for each selected payment and refresh table

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Gitead
2026-05-06 15:12:56 -04:00
parent 4989201c62
commit 1196e2afee
6 changed files with 364 additions and 14 deletions

View File

@@ -98,6 +98,7 @@ export default function PaymentsRecentTable({
>(undefined);
const [selectedPaymentId, setSelectedPaymentId] = useState<number | null>(null);
const [checkedPaymentIds, setCheckedPaymentIds] = useState<Set<number>>(new Set());
const [isMhChecking, setIsMhChecking] = useState(false);
const [isRevertOpen, setIsRevertOpen] = useState(false);
const [revertPaymentId, setRevertPaymentId] = useState<number | null>(null);
@@ -517,11 +518,44 @@ export default function PaymentsRecentTable({
<Button
size="sm"
variant="default"
onClick={() => {
// Logic to be defined later
disabled={isMhChecking}
onClick={async () => {
setIsMhChecking(true);
let successCount = 0;
let failCount = 0;
for (const paymentId of checkedPaymentIds) {
try {
const res = await apiRequest(
"PATCH",
`/api/payments/${paymentId}/mh-payment-check`
);
if (res.ok) {
successCount++;
} else {
const err = await res.json();
console.error(`MH check failed for payment ${paymentId}:`, err.message);
failCount++;
}
} catch (e) {
console.error(`MH check error for payment ${paymentId}:`, e);
failCount++;
}
}
setIsMhChecking(false);
setCheckedPaymentIds(new Set());
await queryClient.invalidateQueries({ queryKey: QK_PAYMENTS_RECENT_BASE });
if (failCount === 0) {
toast({ title: "MH Payment Check Complete", description: `${successCount} record(s) updated.` });
} else {
toast({
title: "MH Payment Check Done",
description: `${successCount} succeeded, ${failCount} failed. Check credentials or claim numbers.`,
variant: "destructive",
});
}
}}
>
Check MH Payment
{isMhChecking ? "Checking..." : "Check MH Payment"}
</Button>
<Button
size="sm"
@@ -548,14 +582,16 @@ export default function PaymentsRecentTable({
/>
</TableHead>
)}
<TableHead>Payment ID</TableHead>
<TableHead>Claim ID</TableHead>
<TableHead>Claim No.</TableHead>
<TableHead>Patient Name</TableHead>
<TableHead>Amount</TableHead>
<TableHead>Service Date</TableHead>
<TableHead>Status</TableHead>
<TableHead>Attachments</TableHead>
<TableHead>MH Paid</TableHead>
<TableHead className="text-right">Actions</TableHead>
<TableHead>Payment ID</TableHead>
<TableHead>Claim ID</TableHead>
</TableRow>
</TableHeader>
<TableBody>
@@ -612,15 +648,9 @@ export default function PaymentsRecentTable({
</TableCell>
)}
<TableCell>
{typeof payment.id === "number"
? `PAY-${payment.id.toString().padStart(4, "0")}`
: "N/A"}
</TableCell>
<TableCell>
{typeof payment.claimId === "number"
? `CLM-${payment.claimId.toString().padStart(4, "0")}`
: "N/A"}
<span className="text-sm font-mono">
{payment.claim?.claimNumber ?? <span className="text-gray-400"></span>}
</span>
</TableCell>
<TableCell>
@@ -710,6 +740,16 @@ export default function PaymentsRecentTable({
)}
</TableCell>
<TableCell>
{payment.mhPaidAmount != null ? (
<span className="text-sm font-medium text-green-700">
${Number(payment.mhPaidAmount).toFixed(2)}
</span>
) : (
<span className="text-xs text-gray-400"></span>
)}
</TableCell>
<TableCell className="text-right">
<div className="flex justify-end space-x-2">
{allowDelete && (
@@ -795,6 +835,18 @@ export default function PaymentsRecentTable({
)}
</div>
</TableCell>
<TableCell className="text-xs text-gray-500">
{typeof payment.id === "number"
? `PAY-${payment.id.toString().padStart(4, "0")}`
: "N/A"}
</TableCell>
<TableCell className="text-xs text-gray-500">
{typeof payment.claimId === "number"
? `CLM-${payment.claimId.toString().padStart(4, "0")}`
: "N/A"}
</TableCell>
</TableRow>
);
})