npiProvider - v3
This commit is contained in:
@@ -39,6 +39,7 @@ import {
|
||||
InputServiceLine,
|
||||
InsertAppointment,
|
||||
MissingTeethStatus,
|
||||
NpiProvider,
|
||||
Patient,
|
||||
Staff,
|
||||
UpdateAppointment,
|
||||
@@ -134,6 +135,17 @@ export function ClaimForm({
|
||||
}
|
||||
}, [staffMembersRaw, staff]);
|
||||
|
||||
// fetching npi providers
|
||||
|
||||
const { data: npiProviders = [] } = useQuery<NpiProvider[]>({
|
||||
queryKey: ["/api/npiProviders/"],
|
||||
queryFn: async () => {
|
||||
const res = await apiRequest("GET", "/api/npiProviders/");
|
||||
if (!res.ok) throw new Error("Failed to fetch NPI providers");
|
||||
return res.json();
|
||||
},
|
||||
});
|
||||
|
||||
// Service date state
|
||||
const [serviceDateValue, setServiceDateValue] = useState<Date>(new Date());
|
||||
const [serviceDate, setServiceDate] = useState<string>(
|
||||
@@ -550,6 +562,16 @@ export function ClaimForm({
|
||||
return;
|
||||
}
|
||||
|
||||
if (!f.npiProvider?.npiNumber) {
|
||||
toast({
|
||||
title: "NPI Provider Required",
|
||||
description: "Please select a NPI Provider.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 1. Create or update appointment
|
||||
let appointmentIdToUse = appointmentId;
|
||||
|
||||
@@ -611,6 +633,7 @@ export function ClaimForm({
|
||||
dateOfBirth: toMMDDYYYY(f.dateOfBirth),
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: Number(staff?.id),
|
||||
npiProvider: f.npiProvider,
|
||||
patientId: patientId,
|
||||
insuranceProvider: "Mass Health",
|
||||
appointmentId: appointmentIdToUse!,
|
||||
@@ -659,6 +682,16 @@ export function ClaimForm({
|
||||
return;
|
||||
}
|
||||
|
||||
if (!f.npiProvider?.npiNumber) {
|
||||
toast({
|
||||
title: "NPI Provider Required",
|
||||
description: "Please select a NPI Provider.",
|
||||
variant: "destructive",
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// 2. Update patient
|
||||
if (patient && typeof patient.id === "number") {
|
||||
const { id, createdAt, userId, ...sanitizedFields } = patient;
|
||||
@@ -682,6 +715,7 @@ export function ClaimForm({
|
||||
dateOfBirth: toMMDDYYYY(f.dateOfBirth),
|
||||
serviceLines: filteredServiceLines,
|
||||
staffId: Number(staff?.id),
|
||||
npiProvider: f.npiProvider,
|
||||
patientId: patientId,
|
||||
insuranceProvider: "Mass Health",
|
||||
insuranceSiteKey: "MH",
|
||||
@@ -1000,6 +1034,41 @@ export function ClaimForm({
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{/* Rendering Npi Provider */}
|
||||
<Label className="flex items-center ml-2">
|
||||
Rendering Provider
|
||||
</Label>
|
||||
|
||||
<Select
|
||||
value={form.npiProvider?.npiNumber || ""}
|
||||
onValueChange={(npiNumber) => {
|
||||
const selected = npiProviders.find(
|
||||
(p) => p.npiNumber === npiNumber,
|
||||
);
|
||||
if (!selected) return;
|
||||
|
||||
setForm((prev) => ({
|
||||
...prev,
|
||||
renderingNpi: {
|
||||
npiNumber: selected.npiNumber,
|
||||
providerName: selected.providerName,
|
||||
},
|
||||
}));
|
||||
}}
|
||||
>
|
||||
<SelectTrigger className="w-56">
|
||||
<SelectValue placeholder="Select NPI Provider" />
|
||||
</SelectTrigger>
|
||||
|
||||
<SelectContent>
|
||||
{npiProviders.map((p) => (
|
||||
<SelectItem key={p.id} value={p.npiNumber}>
|
||||
{p.npiNumber} — {p.providerName}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
|
||||
{/* Map Price Button */}
|
||||
<Button
|
||||
className="ml-4"
|
||||
|
||||
@@ -27,6 +27,9 @@ class AutomationMassHealth:
|
||||
self.remarks = self.claim.get("remarks", "")
|
||||
self.massdhp_username = self.claim.get("massdhpUsername", "")
|
||||
self.massdhp_password = self.claim.get("massdhpPassword", "")
|
||||
self.npiProvider = self.claim.get("npiProvider", {})
|
||||
self.npiNumber = self.npiProvider.get("npiNumber", "")
|
||||
self.npiName = self.npiProvider.get("providerName", "")
|
||||
self.serviceLines = self.claim.get("serviceLines", [])
|
||||
self.missingTeethStatus = self.claim.get("missingTeethStatus", "")
|
||||
self.missingTeeth = self.claim.get("missingTeeth", {})
|
||||
@@ -40,6 +43,39 @@ class AutomationMassHealth:
|
||||
driver = webdriver.Chrome(service=s, options=options)
|
||||
self.driver = driver
|
||||
|
||||
def select_rendering_npi(self, select_element):
|
||||
options = select_element.options
|
||||
|
||||
target_npi = (self.renderingNpiNumber or "").strip()
|
||||
target_name = (self.renderingNpiName or "").strip().lower()
|
||||
|
||||
# 1️⃣ Exact NPI match (value or text)
|
||||
for opt in options:
|
||||
value = (opt.get_attribute("value") or "").strip()
|
||||
text = (opt.text or "").lower()
|
||||
|
||||
if target_npi and (
|
||||
value == target_npi or target_npi in text
|
||||
):
|
||||
opt.click()
|
||||
return True
|
||||
|
||||
# 2️⃣ Name match fallback
|
||||
for opt in options:
|
||||
text = (opt.text or "").lower()
|
||||
if target_name and target_name in text:
|
||||
opt.click()
|
||||
return True
|
||||
|
||||
# 3️⃣ Last fallback → first valid option
|
||||
for opt in options:
|
||||
if opt.get_attribute("value"):
|
||||
opt.click()
|
||||
return True
|
||||
|
||||
raise Exception("No valid Rendering Provider NPI found")
|
||||
|
||||
|
||||
def login(self):
|
||||
wait = WebDriverWait(self.driver, 30)
|
||||
|
||||
@@ -98,7 +134,7 @@ class AutomationMassHealth:
|
||||
# Rendering Provider NPI dropdown
|
||||
npi_dropdown = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="Select1"]')))
|
||||
select_npi = Select(npi_dropdown)
|
||||
select_npi.select_by_index(1)
|
||||
self.select_rendering_npi(select_npi)
|
||||
|
||||
# Office Location dropdown
|
||||
location_dropdown = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="Select2"]')))
|
||||
|
||||
@@ -26,6 +26,9 @@ class AutomationMassHealthPreAuth:
|
||||
self.remarks = self.claim.get("remarks", "")
|
||||
self.massdhp_username = self.claim.get("massdhpUsername", "")
|
||||
self.massdhp_password = self.claim.get("massdhpPassword", "")
|
||||
self.npiProvider = self.claim.get("npiProvider", {})
|
||||
self.npiNumber = self.npiProvider.get("npiNumber", "")
|
||||
self.npiName = self.npiProvider.get("providerName", "")
|
||||
self.serviceLines = self.claim.get("serviceLines", [])
|
||||
self.missingTeethStatus = self.claim.get("missingTeethStatus", "")
|
||||
self.missingTeeth = self.claim.get("missingTeeth", {})
|
||||
@@ -39,6 +42,39 @@ class AutomationMassHealthPreAuth:
|
||||
driver = webdriver.Chrome(service=s, options=options)
|
||||
self.driver = driver
|
||||
|
||||
def select_rendering_npi(self, select_element):
|
||||
options = select_element.options
|
||||
|
||||
target_npi = (self.renderingNpiNumber or "").strip()
|
||||
target_name = (self.renderingNpiName or "").strip().lower()
|
||||
|
||||
# 1️⃣ Exact NPI match (value or text)
|
||||
for opt in options:
|
||||
value = (opt.get_attribute("value") or "").strip()
|
||||
text = (opt.text or "").lower()
|
||||
|
||||
if target_npi and (
|
||||
value == target_npi or target_npi in text
|
||||
):
|
||||
opt.click()
|
||||
return True
|
||||
|
||||
# 2️⃣ Name match fallback
|
||||
for opt in options:
|
||||
text = (opt.text or "").lower()
|
||||
if target_name and target_name in text:
|
||||
opt.click()
|
||||
return True
|
||||
|
||||
# 3️⃣ Last fallback → first valid option
|
||||
for opt in options:
|
||||
if opt.get_attribute("value"):
|
||||
opt.click()
|
||||
return True
|
||||
|
||||
raise Exception("No valid Rendering Provider NPI found")
|
||||
|
||||
|
||||
def login(self):
|
||||
wait = WebDriverWait(self.driver, 30)
|
||||
|
||||
@@ -97,7 +133,7 @@ class AutomationMassHealthPreAuth:
|
||||
# Rendering Provider NPI dropdown
|
||||
npi_dropdown = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="Select1"]')))
|
||||
select_npi = Select(npi_dropdown)
|
||||
select_npi.select_by_index(1)
|
||||
self.select_rendering_npi(select_npi)
|
||||
|
||||
# Office Location dropdown
|
||||
location_dropdown = wait.until(EC.presence_of_element_located((By.XPATH, '//*[@id="Select2"]')))
|
||||
|
||||
@@ -99,6 +99,10 @@ export interface ClaimFormData {
|
||||
serviceDate: string; // YYYY-MM-DD
|
||||
insuranceProvider: string;
|
||||
insuranceSiteKey?: string;
|
||||
npiProvider?: {
|
||||
npiNumber: string;
|
||||
providerName: string;
|
||||
};
|
||||
status: string; // default "pending"
|
||||
serviceLines: InputServiceLine[];
|
||||
claimId?: number;
|
||||
@@ -118,6 +122,10 @@ export interface ClaimPreAuthData {
|
||||
serviceDate: string; // YYYY-MM-DD
|
||||
insuranceProvider: string;
|
||||
insuranceSiteKey?: string;
|
||||
npiProvider?: {
|
||||
npiNumber: string;
|
||||
providerName: string;
|
||||
};
|
||||
status: string; // default "pending"
|
||||
serviceLines: InputServiceLine[];
|
||||
claimFiles?: ClaimFileMeta[];
|
||||
|
||||
Reference in New Issue
Block a user