fix(insuranceId space issue)
This commit is contained in:
@@ -3,6 +3,7 @@ import type { Request, Response } from "express";
|
||||
import { storage } from "../storage";
|
||||
import { z } from "zod";
|
||||
import { insertPatientSchema, updatePatientSchema } from "@repo/db/types";
|
||||
import { normalizeInsuranceId } from "../utils/helpers";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -160,6 +161,18 @@ router.get(
|
||||
// Create a new patient
|
||||
router.post("/", async (req: Request, res: Response): Promise<any> => {
|
||||
try {
|
||||
const body: any = { ...req.body, userId: req.user!.id };
|
||||
|
||||
// Normalize insuranceId early and return clear error if invalid
|
||||
try {
|
||||
const normalized = normalizeInsuranceId(body.insuranceId);
|
||||
body.insuranceId = normalized;
|
||||
} catch (err: any) {
|
||||
return res.status(400).json({
|
||||
message: "Invalid insuranceId",
|
||||
details: err?.message ?? "Invalid insuranceId format",
|
||||
});
|
||||
}
|
||||
// Validate request body
|
||||
const patientData = insertPatientSchema.parse({
|
||||
...req.body,
|
||||
@@ -169,7 +182,7 @@ router.post("/", async (req: Request, res: Response): Promise<any> => {
|
||||
// Check for duplicate insuranceId if it's provided
|
||||
if (patientData.insuranceId) {
|
||||
const existingPatient = await storage.getPatientByInsuranceId(
|
||||
patientData.insuranceId
|
||||
patientData.insuranceId as string
|
||||
);
|
||||
|
||||
if (existingPatient) {
|
||||
@@ -201,6 +214,18 @@ router.put(
|
||||
try {
|
||||
const patientIdParam = req.params.id;
|
||||
|
||||
// Normalize incoming insuranceId (if present)
|
||||
try {
|
||||
if (req.body.insuranceId !== undefined) {
|
||||
req.body.insuranceId = normalizeInsuranceId(req.body.insuranceId);
|
||||
}
|
||||
} catch (err: any) {
|
||||
return res.status(400).json({
|
||||
message: "Invalid insuranceId",
|
||||
details: err?.message ?? "Invalid insuranceId format",
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure that patientIdParam exists and is a valid number
|
||||
if (!patientIdParam) {
|
||||
return res.status(400).json({ message: "Patient ID is required" });
|
||||
@@ -223,7 +248,7 @@ router.put(
|
||||
patientData.insuranceId !== existingPatient.insuranceId
|
||||
) {
|
||||
const duplicatePatient = await storage.getPatientByInsuranceId(
|
||||
patientData.insuranceId
|
||||
patientData.insuranceId as string
|
||||
);
|
||||
if (duplicatePatient && duplicatePatient.id !== patientId) {
|
||||
return res.status(409).json({
|
||||
|
||||
@@ -87,7 +87,7 @@ export const patientsStorage: IStorage = {
|
||||
try {
|
||||
return await db.patient.update({
|
||||
where: { id },
|
||||
data: updateData,
|
||||
data: updateData as Patient,
|
||||
});
|
||||
} catch (err) {
|
||||
throw new Error(`Patient with ID ${id} not found`);
|
||||
|
||||
27
apps/Backend/src/utils/helpers.ts
Normal file
27
apps/Backend/src/utils/helpers.ts
Normal file
@@ -0,0 +1,27 @@
|
||||
export function normalizeInsuranceId(raw: unknown): string | undefined {
|
||||
if (raw === undefined || raw === null) return undefined;
|
||||
|
||||
// Accept numbers too (e.g. 12345), but prefer strings
|
||||
let s: string;
|
||||
if (typeof raw === "number") {
|
||||
s = String(raw);
|
||||
} else if (typeof raw === "string") {
|
||||
s = raw;
|
||||
} else {
|
||||
// Not acceptable type
|
||||
throw new Error("Insurance ID must be a numeric string.");
|
||||
}
|
||||
|
||||
// Remove all whitespace
|
||||
const cleaned = s.replace(/\s+/g, "");
|
||||
|
||||
// If empty after cleaning, treat as undefined
|
||||
if (cleaned === "") return undefined;
|
||||
|
||||
// Only digits allowed (since you said it's numeric)
|
||||
if (!/^\d+$/.test(cleaned)) {
|
||||
throw new Error("Insurance ID must contain only digits.");
|
||||
}
|
||||
|
||||
return cleaned;
|
||||
}
|
||||
@@ -1,14 +1,44 @@
|
||||
import { PatientUncheckedCreateInputObjectSchema } from "@repo/db/usedSchemas";
|
||||
import {z} from "zod";
|
||||
import { z } from "zod";
|
||||
|
||||
export type Patient = z.infer<typeof PatientUncheckedCreateInputObjectSchema>;
|
||||
|
||||
export const insuranceIdSchema = z.preprocess(
|
||||
(val) => {
|
||||
if (val === undefined || val === null) return undefined;
|
||||
|
||||
// Accept numbers and strings
|
||||
if (typeof val === "number") {
|
||||
return String(val).replace(/\s+/g, "");
|
||||
}
|
||||
if (typeof val === "string") {
|
||||
const cleaned = val.replace(/\s+/g, "");
|
||||
if (cleaned === "") return undefined;
|
||||
return cleaned;
|
||||
}
|
||||
return val;
|
||||
},
|
||||
// After preprocess, require digits-only string (or optional nullable)
|
||||
z
|
||||
.string()
|
||||
.regex(/^\d+$/, { message: "Insurance ID must contain only digits" })
|
||||
.min(1)
|
||||
.max(32)
|
||||
.optional()
|
||||
.nullable()
|
||||
);
|
||||
|
||||
export const insertPatientSchema = (
|
||||
PatientUncheckedCreateInputObjectSchema as unknown as z.ZodObject<any>
|
||||
).omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
});
|
||||
)
|
||||
.omit({
|
||||
id: true,
|
||||
createdAt: true,
|
||||
})
|
||||
.extend({
|
||||
insuranceId: insuranceIdSchema, // enforce numeric insuranceId
|
||||
});
|
||||
|
||||
export type InsertPatient = z.infer<typeof insertPatientSchema>;
|
||||
|
||||
export const updatePatientSchema = (
|
||||
@@ -19,6 +49,9 @@ export const updatePatientSchema = (
|
||||
createdAt: true,
|
||||
userId: true,
|
||||
})
|
||||
.partial();
|
||||
.partial()
|
||||
.extend({
|
||||
insuranceId: insuranceIdSchema, // enforce numeric insuranceId
|
||||
});
|
||||
|
||||
export type UpdatePatient = z.infer<typeof updatePatientSchema>;
|
||||
Reference in New Issue
Block a user