Adds an optional Provider (NPI) select to the Edit Appointment form, sourced from Settings > NPI Providers. The AI "Claim for Column" batch flow now prefers the appointment's own provider when resolving which provider Selenium should select on the insurance site (e.g. MassHealth rendering provider dropdown), falling back to the existing per-procedure selection, active claim, or first configured provider. Also resyncs packages/db's committed compiled schema/client artifacts with their .ts sources — they had drifted out of sync (some untouched since July), which was silently stripping the new npiProviderId field via stale .strict() zod schemas. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
761 lines
21 KiB
Plaintext
Executable File
761 lines
21 KiB
Plaintext
Executable File
// This is your Prisma schema file,
|
|
// learn more about it in the docs: https://pris.ly/d/prisma-schema
|
|
|
|
// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
|
|
// Try Prisma Accelerate: https://pris.ly/cli/accelerate-init
|
|
|
|
generator client {
|
|
provider = "prisma-client-js"
|
|
output = "../generated/prisma"
|
|
}
|
|
|
|
generator zod {
|
|
provider = "prisma-zod-generator"
|
|
output = "../shared/" // Zod schemas will be generated here inside `db/shared`
|
|
}
|
|
|
|
datasource db {
|
|
provider = "postgresql"
|
|
}
|
|
|
|
model User {
|
|
id Int @id @default(autoincrement())
|
|
username String @unique
|
|
password String
|
|
autoBackupEnabled Boolean @default(true)
|
|
autoBackupHour Int @default(20)
|
|
usbBackupEnabled Boolean @default(false)
|
|
usbBackupHour Int @default(21)
|
|
autoMhCheckEnabled Boolean @default(false)
|
|
autoMhCheckDayOfWeek Int @default(1)
|
|
autoMhCheckHour Int @default(13)
|
|
patients Patient[]
|
|
appointments Appointment[]
|
|
staff Staff[]
|
|
npiProviders NpiProvider[]
|
|
claims Claim[]
|
|
insuranceCredentials InsuranceCredential[]
|
|
shoppingVendors ShoppingVendor[]
|
|
updatedPayments Payment[] @relation("PaymentUpdatedBy")
|
|
backups DatabaseBackup[]
|
|
backupDestinations BackupDestination[]
|
|
notifications Notification[]
|
|
cloudFolders CloudFolder[]
|
|
cloudFiles CloudFile[]
|
|
communications Communication[]
|
|
twilioSettings TwilioSettings?
|
|
aiSettings AiSettings?
|
|
officeHours OfficeHours?
|
|
officeContact OfficeContact?
|
|
procedureTimeslot ProcedureTimeslot?
|
|
insuranceContacts InsuranceContact[]
|
|
patientConversations PatientConversation[]
|
|
labRxTemplates LabRxTemplate[]
|
|
seleniumSettings SeleniumSettings?
|
|
}
|
|
|
|
model Patient {
|
|
id Int @id @default(autoincrement())
|
|
firstName String
|
|
lastName String
|
|
dateOfBirth DateTime? @db.Date
|
|
gender String
|
|
phone String
|
|
email String?
|
|
address String?
|
|
city String?
|
|
zipCode String?
|
|
insuranceProvider String?
|
|
insuranceId String?
|
|
groupNumber String?
|
|
policyHolder String?
|
|
allergies String?
|
|
medicalConditions String?
|
|
preferredLanguage String? @default("English")
|
|
status PatientStatus @default(UNKNOWN)
|
|
userId Int
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id])
|
|
appointments Appointment[]
|
|
procedures AppointmentProcedure[]
|
|
claims Claim[]
|
|
groups PdfGroup[]
|
|
payment Payment[]
|
|
communications Communication[]
|
|
documents PatientDocument[]
|
|
conversation PatientConversation?
|
|
cloudFolders CloudFolder[] @relation("PatientCloudFolder")
|
|
|
|
@@index([insuranceId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
enum PatientStatus {
|
|
ACTIVE
|
|
INACTIVE
|
|
UNKNOWN
|
|
PLAN_NOT_ACCEPTED
|
|
}
|
|
|
|
model Appointment {
|
|
id Int @id @default(autoincrement())
|
|
patientId Int
|
|
userId Int
|
|
staffId Int
|
|
npiProviderId Int?
|
|
title String
|
|
date DateTime @db.Date
|
|
startTime String // Store time as "hh:mm"
|
|
endTime String // Store time as "hh:mm"
|
|
type String // e.g., "checkup", "cleaning", "filling", etc.
|
|
typeLocked Boolean @default(false) // true = user manually set; auto-sync will not overwrite
|
|
notes String?
|
|
procedureCodeNotes String?
|
|
status String @default("scheduled") // "scheduled", "completed", "cancelled", "no-show"
|
|
movedByAi Boolean @default(false)
|
|
createdAt DateTime @default(now())
|
|
|
|
eligibilityStatus PatientStatus @default(UNKNOWN)
|
|
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id])
|
|
staff Staff? @relation(fields: [staffId], references: [id])
|
|
npiProvider NpiProvider? @relation(fields: [npiProviderId], references: [id])
|
|
procedures AppointmentProcedure[]
|
|
claims Claim[]
|
|
files AppointmentFile[]
|
|
|
|
@@index([patientId])
|
|
@@index([date])
|
|
}
|
|
|
|
model AppointmentFile {
|
|
id Int @id @default(autoincrement())
|
|
appointmentId Int
|
|
filename String
|
|
mimeType String?
|
|
filePath String?
|
|
|
|
appointment Appointment @relation(fields: [appointmentId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([appointmentId])
|
|
}
|
|
|
|
model Staff {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
name String
|
|
email String?
|
|
role String // e.g., "Dentist", "Hygienist", "Assistant"
|
|
phone String?
|
|
createdAt DateTime @default(now())
|
|
user User? @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
appointments Appointment[]
|
|
claims Claim[] @relation("ClaimStaff")
|
|
}
|
|
|
|
model NpiProvider {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
npiNumber String
|
|
providerName String
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
claims Claim[]
|
|
payments Payment[]
|
|
commissionBatches CommissionBatch[]
|
|
appointmentProcedures AppointmentProcedure[]
|
|
appointments Appointment[]
|
|
|
|
@@unique([userId, npiNumber])
|
|
@@index([userId])
|
|
}
|
|
|
|
enum ProcedureSource {
|
|
COMBO
|
|
MANUAL
|
|
}
|
|
|
|
model AppointmentProcedure {
|
|
id Int @id @default(autoincrement())
|
|
appointmentId Int
|
|
patientId Int
|
|
npiProviderId Int?
|
|
|
|
procedureCode String
|
|
procedureLabel String?
|
|
fee Decimal? @db.Decimal(10, 2)
|
|
|
|
category String?
|
|
|
|
toothNumber String?
|
|
toothSurface String?
|
|
oralCavityArea String?
|
|
|
|
source ProcedureSource @default(MANUAL)
|
|
comboKey String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
appointment Appointment @relation(fields: [appointmentId], references: [id], onDelete: Cascade)
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
npiProvider NpiProvider? @relation(fields: [npiProviderId], references: [id])
|
|
|
|
@@index([appointmentId])
|
|
@@index([patientId])
|
|
}
|
|
|
|
model Claim {
|
|
id Int @id @default(autoincrement())
|
|
patientId Int
|
|
/// @zod.number.int().nullable().optional()
|
|
appointmentId Int?
|
|
userId Int
|
|
staffId Int
|
|
patientName String
|
|
memberId String
|
|
dateOfBirth DateTime @db.Date
|
|
remarks String
|
|
missingTeethStatus MissingTeethStatus @default(No_missing)
|
|
missingTeeth Json? // { "T_14": "X", "T_G": "O", ... }
|
|
serviceDate DateTime
|
|
insuranceProvider String // e.g., "Delta MA"
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
status ClaimStatus @default(PENDING)
|
|
claimNumber String?
|
|
preAuthNumber String?
|
|
npiProviderId Int?
|
|
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
appointment Appointment? @relation(fields: [appointmentId], references: [id], onDelete: Cascade)
|
|
user User? @relation(fields: [userId], references: [id])
|
|
staff Staff? @relation("ClaimStaff", fields: [staffId], references: [id])
|
|
npiProvider NpiProvider? @relation(fields: [npiProviderId], references: [id])
|
|
|
|
serviceLines ServiceLine[]
|
|
claimFiles ClaimFile[]
|
|
payment Payment?
|
|
}
|
|
|
|
enum ClaimStatus {
|
|
PENDING
|
|
APPROVED
|
|
CANCELLED
|
|
REVIEW
|
|
VOID
|
|
PREAUTH
|
|
}
|
|
|
|
enum MissingTeethStatus {
|
|
No_missing
|
|
endentulous
|
|
Yes_missing
|
|
}
|
|
|
|
model ServiceLine {
|
|
id Int @id @default(autoincrement())
|
|
claimId Int?
|
|
paymentId Int?
|
|
procedureCode String
|
|
procedureDate DateTime @db.Date
|
|
quad String?
|
|
arch String?
|
|
toothNumber String?
|
|
toothSurface String?
|
|
icn String?
|
|
paidCode String?
|
|
allowedAmount Decimal? @db.Decimal(10, 2)
|
|
totalBilled Decimal @db.Decimal(10, 2)
|
|
totalPaid Decimal @default(0.00) @db.Decimal(10, 2)
|
|
totalAdjusted Decimal @default(0.00) @db.Decimal(10, 2)
|
|
totalDue Decimal @default(0.00) @db.Decimal(10, 2)
|
|
status ServiceLineStatus @default(UNPAID)
|
|
|
|
claim Claim? @relation(fields: [claimId], references: [id], onDelete: Cascade)
|
|
payment Payment? @relation(fields: [paymentId], references: [id], onDelete: Cascade)
|
|
|
|
serviceLineTransactions ServiceLineTransaction[]
|
|
}
|
|
|
|
enum ServiceLineStatus {
|
|
PENDING
|
|
PARTIALLY_PAID
|
|
PAID
|
|
UNPAID
|
|
ADJUSTED
|
|
OVERPAID
|
|
DENIED
|
|
}
|
|
|
|
model ClaimFile {
|
|
id Int @id @default(autoincrement())
|
|
claimId Int
|
|
filename String
|
|
mimeType String
|
|
filePath String?
|
|
|
|
claim Claim @relation(fields: [claimId], references: [id], onDelete: Cascade)
|
|
}
|
|
|
|
model InsuranceCredential {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
siteKey String
|
|
username String
|
|
password String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([userId, siteKey])
|
|
@@index([userId])
|
|
}
|
|
|
|
model ShoppingVendor {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
vendorName String
|
|
websiteUrl String
|
|
loginUsername String
|
|
loginPassword String
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
}
|
|
|
|
model PdfGroup {
|
|
id Int @id @default(autoincrement())
|
|
title String
|
|
titleKey PdfTitleKey @default(OTHER)
|
|
createdAt DateTime @default(now())
|
|
patientId Int
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
pdfs PdfFile[]
|
|
|
|
@@index([patientId])
|
|
@@index([titleKey])
|
|
}
|
|
|
|
model PdfFile {
|
|
id Int @id @default(autoincrement())
|
|
filename String
|
|
pdfData Bytes
|
|
uploadedAt DateTime @default(now())
|
|
groupId Int
|
|
group PdfGroup @relation(fields: [groupId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([groupId])
|
|
}
|
|
|
|
enum PdfTitleKey {
|
|
INSURANCE_CLAIM
|
|
INSURANCE_CLAIM_PREAUTH
|
|
ELIGIBILITY_STATUS
|
|
CLAIM_STATUS
|
|
OTHER
|
|
}
|
|
|
|
model Payment {
|
|
id Int @id @default(autoincrement())
|
|
claimId Int? @unique
|
|
patientId Int
|
|
userId Int
|
|
updatedById Int?
|
|
npiProviderId Int?
|
|
totalBilled Decimal @db.Decimal(10, 2)
|
|
totalPaid Decimal @default(0.00) @db.Decimal(10, 2)
|
|
totalAdjusted Decimal @default(0.00) @db.Decimal(10, 2)
|
|
totalDue Decimal @db.Decimal(10, 2)
|
|
mhPaidAmount Decimal? @db.Decimal(10, 2)
|
|
copayment Decimal @default(0.00) @db.Decimal(10, 2)
|
|
adjustment Decimal @default(0.00) @db.Decimal(10, 2)
|
|
status PaymentStatus @default(PENDING)
|
|
notes String?
|
|
icn String?
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
claim Claim? @relation(fields: [claimId], references: [id], onDelete: Cascade)
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
updatedBy User? @relation("PaymentUpdatedBy", fields: [updatedById], references: [id])
|
|
npiProvider NpiProvider? @relation(fields: [npiProviderId], references: [id])
|
|
serviceLineTransactions ServiceLineTransaction[]
|
|
serviceLines ServiceLine[]
|
|
commissionBatchItems CommissionBatchItem[]
|
|
|
|
@@index([claimId])
|
|
@@index([patientId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
model ServiceLineTransaction {
|
|
id Int @id @default(autoincrement())
|
|
paymentId Int
|
|
serviceLineId Int
|
|
transactionId String?
|
|
paidAmount Decimal @db.Decimal(10, 2)
|
|
adjustedAmount Decimal @default(0.00) @db.Decimal(10, 2)
|
|
method PaymentMethod
|
|
receivedDate DateTime
|
|
payerName String?
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
|
|
payment Payment @relation(fields: [paymentId], references: [id], onDelete: Cascade)
|
|
serviceLine ServiceLine @relation(fields: [serviceLineId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([paymentId])
|
|
@@index([serviceLineId])
|
|
}
|
|
|
|
enum PaymentStatus {
|
|
PENDING
|
|
PARTIALLY_PAID
|
|
PAID
|
|
OVERPAID
|
|
DENIED
|
|
VOID
|
|
}
|
|
|
|
enum PaymentMethod {
|
|
EFT
|
|
CHECK
|
|
CASH
|
|
CARD
|
|
OTHER
|
|
}
|
|
|
|
// Database management page
|
|
model DatabaseBackup {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
createdAt DateTime @default(now())
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
model BackupDestination {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
path String
|
|
isActive Boolean @default(true)
|
|
createdAt DateTime @default(now())
|
|
|
|
user User @relation(fields: [userId], references: [id])
|
|
}
|
|
|
|
model Notification {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
type NotificationTypes
|
|
message String
|
|
createdAt DateTime @default(now())
|
|
read Boolean @default(false)
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@index([createdAt])
|
|
}
|
|
|
|
enum NotificationTypes {
|
|
BACKUP
|
|
CLAIM
|
|
PAYMENT
|
|
ETC
|
|
}
|
|
|
|
// Cron job execution log
|
|
model CronJobLog {
|
|
id Int @id @default(autoincrement())
|
|
jobName String // e.g. "local-backup", "usb-backup"
|
|
status String // "success" | "failed" | "skipped"
|
|
startedAt DateTime
|
|
completedAt DateTime?
|
|
durationMs Int?
|
|
errorMessage String?
|
|
|
|
@@index([jobName])
|
|
@@index([startedAt])
|
|
@@index([status])
|
|
}
|
|
|
|
model CloudFolder {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
name String
|
|
parentId Int?
|
|
patientId Int?
|
|
parent CloudFolder? @relation("FolderChildren", fields: [parentId], references: [id], onDelete: Cascade)
|
|
children CloudFolder[] @relation("FolderChildren")
|
|
user User @relation(fields: [userId], references: [id])
|
|
patient Patient? @relation("PatientCloudFolder", fields: [patientId], references: [id], onDelete: SetNull)
|
|
files CloudFile[]
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
@@unique([userId, parentId, name]) // prevents sibling folder name duplicates
|
|
@@index([parentId])
|
|
@@index([patientId])
|
|
}
|
|
|
|
model CloudFile {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
name String
|
|
mimeType String?
|
|
fileSize BigInt @db.BigInt
|
|
folderId Int? // optional: null => root
|
|
isComplete Boolean @default(false) // upload completed?
|
|
totalChunks Int? // optional: expected number of chunks
|
|
diskPath String? // relative path on disk under uploads/
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
user User @relation(fields: [userId], references: [id])
|
|
folder CloudFolder? @relation(fields: [folderId], references: [id], onDelete: SetNull)
|
|
|
|
chunks CloudFileChunk[]
|
|
|
|
@@index([folderId])
|
|
}
|
|
|
|
model CloudFileChunk {
|
|
id Int @id @default(autoincrement())
|
|
fileId Int
|
|
seq Int
|
|
data Bytes
|
|
createdAt DateTime @default(now())
|
|
|
|
file CloudFile @relation(fields: [fileId], references: [id], onDelete: Cascade)
|
|
|
|
@@unique([fileId, seq])
|
|
@@index([fileId, seq])
|
|
}
|
|
|
|
// patient-connection-
|
|
enum CommunicationChannel {
|
|
sms
|
|
voice
|
|
}
|
|
|
|
enum CommunicationDirection {
|
|
outbound
|
|
inbound
|
|
}
|
|
|
|
enum CommunicationStatus {
|
|
queued
|
|
sent
|
|
delivered
|
|
failed
|
|
completed
|
|
busy
|
|
no_answer
|
|
}
|
|
|
|
model Communication {
|
|
id Int @id @default(autoincrement())
|
|
patientId Int
|
|
userId Int?
|
|
|
|
channel CommunicationChannel
|
|
direction CommunicationDirection
|
|
status CommunicationStatus
|
|
|
|
body String?
|
|
callDuration Int?
|
|
twilioSid String?
|
|
|
|
createdAt DateTime @default(now())
|
|
|
|
// Relations
|
|
patient Patient @relation(fields: [patientId], references: [id])
|
|
user User? @relation(fields: [userId], references: [id])
|
|
|
|
@@map("communications")
|
|
}
|
|
|
|
model PatientDocument {
|
|
id Int @id @default(autoincrement())
|
|
patientId Int
|
|
filename String
|
|
originalName String
|
|
mimeType String
|
|
fileSize BigInt
|
|
filePath String
|
|
uploadedAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([patientId])
|
|
@@index([uploadedAt])
|
|
}
|
|
|
|
model TwilioSettings {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @unique
|
|
accountSid String
|
|
authToken String
|
|
phoneNumber String
|
|
greetingMessage String?
|
|
templates Json?
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("twilio_settings")
|
|
}
|
|
|
|
model AiSettings {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @unique
|
|
apiKey String
|
|
aiEnabled Boolean @default(true)
|
|
openAiKey String @default("")
|
|
openAiEnabled Boolean @default(false)
|
|
claudeAiKey String @default("")
|
|
claudeAiEnabled Boolean @default(false)
|
|
claudeAiModel String @default("claude-haiku-4-5-20251001")
|
|
openAiModel String @default("gpt-5.2")
|
|
googleAiModel String @default("gemini-2.5-flash")
|
|
dentalMgmtKey String @default("")
|
|
dentalMgmtEnabled Boolean @default(false)
|
|
afterHoursEnabled Boolean @default(true)
|
|
openPhoneReply Boolean @default(false)
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("ai_settings")
|
|
}
|
|
|
|
model OfficeHours {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @unique
|
|
data Json
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("office_hours")
|
|
}
|
|
|
|
model OfficeContact {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @unique
|
|
officeName String?
|
|
receptionistName String?
|
|
dentistName String?
|
|
phoneNumber String?
|
|
email String?
|
|
fax String?
|
|
streetAddress String?
|
|
city String?
|
|
state String?
|
|
zipCode String?
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("office_contact")
|
|
}
|
|
|
|
model InsuranceContact {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
name String
|
|
phoneNumber String?
|
|
createdAt DateTime @default(now())
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("insurance_contact")
|
|
}
|
|
|
|
model ProcedureTimeslot {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @unique
|
|
data Json
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("procedure_timeslot")
|
|
}
|
|
|
|
model PatientConversation {
|
|
id Int @id @default(autoincrement())
|
|
patientId Int @unique
|
|
userId Int
|
|
stage String @default("initial")
|
|
aiHandoff Boolean @default(true)
|
|
updatedAt DateTime @updatedAt
|
|
|
|
patient Patient @relation(fields: [patientId], references: [id], onDelete: Cascade)
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("patient_conversation")
|
|
}
|
|
|
|
model LabRxTemplate {
|
|
id Int @id @default(autoincrement())
|
|
userId Int
|
|
name String
|
|
labName String?
|
|
labPhone String?
|
|
labFax String?
|
|
labAddress String?
|
|
labAccount String?
|
|
caseType String?
|
|
material String?
|
|
instructions String?
|
|
sortOrder Int @default(0)
|
|
createdAt DateTime @default(now())
|
|
updatedAt DateTime @updatedAt
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@index([userId])
|
|
@@map("lab_rx_template")
|
|
}
|
|
|
|
// Commission tracking
|
|
model CommissionBatch {
|
|
id Int @id @default(autoincrement())
|
|
npiProviderId Int
|
|
totalCollection Decimal @db.Decimal(14, 2)
|
|
commissionAmount Decimal @db.Decimal(14, 2)
|
|
notes String?
|
|
createdAt DateTime @default(now())
|
|
|
|
npiProvider NpiProvider @relation(fields: [npiProviderId], references: [id])
|
|
items CommissionBatchItem[]
|
|
|
|
@@index([npiProviderId])
|
|
}
|
|
|
|
model CommissionBatchItem {
|
|
id Int @id @default(autoincrement())
|
|
commissionBatchId Int
|
|
paymentId Int
|
|
collectionAmount Decimal @db.Decimal(14, 2)
|
|
|
|
commissionBatch CommissionBatch @relation(fields: [commissionBatchId], references: [id], onDelete: Cascade)
|
|
payment Payment @relation(fields: [paymentId], references: [id])
|
|
|
|
@@unique([commissionBatchId, paymentId])
|
|
@@index([paymentId])
|
|
}
|
|
|
|
model SeleniumSettings {
|
|
id Int @id @default(autoincrement())
|
|
userId Int @unique
|
|
paymentGroupId String @default("")
|
|
|
|
user User @relation(fields: [userId], references: [id], onDelete: Cascade)
|
|
|
|
@@map("selenium_settings")
|
|
}
|