187 lines
5.2 KiB
TypeScript
Executable File
187 lines
5.2 KiB
TypeScript
Executable File
import {
|
|
Appointment,
|
|
AppointmentProcedure,
|
|
InsertAppointmentProcedure,
|
|
Patient,
|
|
UpdateAppointmentProcedure,
|
|
} from "@repo/db/types";
|
|
import { prisma as db } from "@repo/db/client";
|
|
|
|
export interface AppointmentFileMeta {
|
|
filename: string;
|
|
mimeType?: string | null;
|
|
filePath?: string | null;
|
|
}
|
|
|
|
export interface IAppointmentProceduresStorage {
|
|
getByAppointmentId(appointmentId: number): Promise<AppointmentProcedure[]>;
|
|
getPrefillDataByAppointmentId(appointmentId: number): Promise<{
|
|
appointment: Appointment;
|
|
patient: Patient;
|
|
procedures: AppointmentProcedure[];
|
|
npiProviderId: number | null;
|
|
appointmentFiles: AppointmentFileMeta[];
|
|
} | null>;
|
|
saveForAppointment(params: {
|
|
appointmentId: number;
|
|
patientId: number;
|
|
npiProviderId: number | null;
|
|
procedures: Array<{
|
|
procedureCode: string;
|
|
fee?: number | null;
|
|
toothNumber?: string | null;
|
|
toothSurface?: string | null;
|
|
}>;
|
|
attachments?: AppointmentFileMeta[];
|
|
}): Promise<number>;
|
|
|
|
createProcedure(
|
|
data: InsertAppointmentProcedure
|
|
): Promise<AppointmentProcedure>;
|
|
createProceduresBulk(data: InsertAppointmentProcedure[]): Promise<number>;
|
|
updateProcedure(
|
|
id: number,
|
|
data: UpdateAppointmentProcedure
|
|
): Promise<AppointmentProcedure>;
|
|
deleteProcedure(id: number): Promise<void>;
|
|
clearByAppointmentId(appointmentId: number): Promise<void>;
|
|
getAppointmentFiles(appointmentId: number): Promise<AppointmentFileMeta[]>;
|
|
getAppointmentIdsWithProcedures(ids: number[]): Promise<Set<number>>;
|
|
}
|
|
|
|
export const appointmentProceduresStorage: IAppointmentProceduresStorage = {
|
|
async getByAppointmentId(
|
|
appointmentId: number
|
|
): Promise<AppointmentProcedure[]> {
|
|
return db.appointmentProcedure.findMany({
|
|
where: { appointmentId },
|
|
orderBy: { createdAt: "asc" },
|
|
});
|
|
},
|
|
|
|
async getPrefillDataByAppointmentId(appointmentId: number) {
|
|
const appointment = await db.appointment.findUnique({
|
|
where: { id: appointmentId },
|
|
include: {
|
|
patient: true,
|
|
procedures: {
|
|
orderBy: { createdAt: "asc" },
|
|
},
|
|
files: {
|
|
orderBy: { id: "asc" },
|
|
},
|
|
},
|
|
});
|
|
|
|
if (!appointment) {
|
|
return null;
|
|
}
|
|
|
|
const npiProviderId = appointment.procedures[0]?.npiProviderId ?? null;
|
|
|
|
return {
|
|
appointment,
|
|
patient: appointment.patient,
|
|
procedures: appointment.procedures,
|
|
npiProviderId,
|
|
appointmentFiles: (appointment.files as any[]).map((f) => ({
|
|
id: f.id,
|
|
filename: f.filename,
|
|
mimeType: f.mimeType,
|
|
filePath: f.filePath,
|
|
})),
|
|
};
|
|
},
|
|
|
|
async saveForAppointment({ appointmentId, patientId, npiProviderId, procedures, attachments }) {
|
|
await db.appointmentProcedure.deleteMany({ where: { appointmentId } });
|
|
if (attachments?.length) {
|
|
await db.appointmentFile.deleteMany({ where: { appointmentId } });
|
|
await db.appointmentFile.createMany({
|
|
data: attachments.map((a) => ({
|
|
appointmentId,
|
|
filename: a.filename,
|
|
mimeType: a.mimeType ?? null,
|
|
filePath: a.filePath ?? null,
|
|
})),
|
|
});
|
|
}
|
|
if (!procedures.length) return 0;
|
|
const result = await db.appointmentProcedure.createMany({
|
|
data: procedures.map((p) => ({
|
|
appointmentId,
|
|
patientId,
|
|
npiProviderId: npiProviderId ?? null,
|
|
procedureCode: p.procedureCode,
|
|
fee: p.fee != null ? p.fee : null,
|
|
toothNumber: p.toothNumber || null,
|
|
toothSurface: p.toothSurface || null,
|
|
source: "MANUAL" as const,
|
|
})),
|
|
});
|
|
return result.count;
|
|
},
|
|
|
|
async createProcedure(
|
|
data: InsertAppointmentProcedure
|
|
): Promise<AppointmentProcedure> {
|
|
return db.appointmentProcedure.create({
|
|
data: data as AppointmentProcedure,
|
|
});
|
|
},
|
|
|
|
async createProceduresBulk(
|
|
data: InsertAppointmentProcedure[]
|
|
): Promise<number> {
|
|
const result = await db.appointmentProcedure.createMany({
|
|
data: data as any[],
|
|
});
|
|
return result.count;
|
|
},
|
|
|
|
async updateProcedure(
|
|
id: number,
|
|
data: UpdateAppointmentProcedure
|
|
): Promise<AppointmentProcedure> {
|
|
return db.appointmentProcedure.update({
|
|
where: { id },
|
|
data: data as any,
|
|
});
|
|
},
|
|
|
|
async deleteProcedure(id: number): Promise<void> {
|
|
await db.appointmentProcedure.delete({
|
|
where: { id },
|
|
});
|
|
},
|
|
|
|
async clearByAppointmentId(appointmentId: number): Promise<void> {
|
|
await db.appointmentProcedure.deleteMany({
|
|
where: { appointmentId },
|
|
});
|
|
},
|
|
|
|
async getAppointmentIdsWithProcedures(ids: number[]): Promise<Set<number>> {
|
|
if (!ids.length) return new Set();
|
|
const rows = await db.appointmentProcedure.findMany({
|
|
where: { appointmentId: { in: ids } },
|
|
select: { appointmentId: true },
|
|
distinct: ["appointmentId"],
|
|
});
|
|
return new Set(rows.map((r: any) => r.appointmentId));
|
|
},
|
|
|
|
async getAppointmentFiles(appointmentId: number): Promise<AppointmentFileMeta[]> {
|
|
const rows = await db.appointmentFile.findMany({
|
|
where: { appointmentId },
|
|
orderBy: { id: "asc" },
|
|
});
|
|
return rows.map((f: any) => ({
|
|
id: f.id,
|
|
filename: f.filename,
|
|
mimeType: f.mimeType,
|
|
filePath: f.filePath,
|
|
}));
|
|
},
|
|
};
|