From 1ca4072ad350252e2c136c8d093b33109df52f7d Mon Sep 17 00:00:00 2001 From: vipul674 Date: Sat, 13 Jun 2026 15:09:50 +0530 Subject: [PATCH 1/2] fix(batch): return unknown for malformed expiry dates --- apps/api/src/routes/batch.ts | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/apps/api/src/routes/batch.ts b/apps/api/src/routes/batch.ts index af56b02b1..c0ac24ea9 100644 --- a/apps/api/src/routes/batch.ts +++ b/apps/api/src/routes/batch.ts @@ -12,6 +12,7 @@ function getExpiryStatus(expiryDate: string | null): "green" | "yellow" | "red" if (!expiryDate) return "unknown"; const now = new Date(); const expiry = new Date(expiryDate); + if (isNaN(expiry.getTime())) return "unknown"; const diffMs = expiry.getTime() - now.getTime(); const diffMonths = diffMs / (1000 * 60 * 60 * 24 * 30); @@ -116,7 +117,11 @@ router.get("/:batchNumber", batchLimiter, async (req: Request, res: Response) => .maybeSingle(); if (batchError) { - logger.error({ message: "Batch lookup failed", error: batchError, route: "/api/verify/batch" }); + logger.error({ + message: "Batch lookup failed", + error: batchError, + route: "/api/verify/batch", + }); res.status(500).json({ error: "Database lookup failed" }); return; } @@ -133,7 +138,11 @@ router.get("/:batchNumber", batchLimiter, async (req: Request, res: Response) => .maybeSingle(); if (medicineError) { - logger.error({ message: "Medicine fallback lookup failed", error: medicineError, route: "/api/verify/batch" }); + logger.error({ + message: "Medicine fallback lookup failed", + error: medicineError, + route: "/api/verify/batch", + }); res.status(500).json({ error: "Database lookup failed" }); return; } @@ -259,7 +268,11 @@ router.get("/:batchNumber", batchLimiter, async (req: Request, res: Response) => }); } catch (err: unknown) { const message = err instanceof Error ? err.message : "Unknown error"; - logger.error({ message: "Batch traceability error", error: message, route: "/api/verify/batch" }); + logger.error({ + message: "Batch traceability error", + error: message, + route: "/api/verify/batch", + }); res.status(500).json({ error: "Internal server error" }); } }); @@ -343,7 +356,11 @@ router.post("/report", batchLimiter, async (req: Request, res: Response) => { }); if (error) { - logger.error({ message: "Failed to insert batch report", error, route: "/api/verify/batch/report" }); + logger.error({ + message: "Failed to insert batch report", + error, + route: "/api/verify/batch/report", + }); res.status(500).json({ error: "Failed to submit report" }); return; } @@ -354,7 +371,11 @@ router.post("/report", batchLimiter, async (req: Request, res: Response) => { }); } catch (err: unknown) { const message = err instanceof Error ? err.message : "Unknown error"; - logger.error({ message: "Batch report error", error: message, route: "/api/verify/batch/report" }); + logger.error({ + message: "Batch report error", + error: message, + route: "/api/verify/batch/report", + }); res.status(500).json({ error: "Internal server error" }); } }); From a1c20625860c4170bf1cdc4817bcad34b9746aad Mon Sep 17 00:00:00 2001 From: vipul674 Date: Sun, 14 Jun 2026 17:00:33 +0530 Subject: [PATCH 2/2] test(batch): add 5 expiry status test cases null expiry_date, malformed date, expired, near-expiry, and future date. Closes #1799 --- apps/api/tests/batch.test.ts | 194 +++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) diff --git a/apps/api/tests/batch.test.ts b/apps/api/tests/batch.test.ts index 291325027..c62720417 100644 --- a/apps/api/tests/batch.test.ts +++ b/apps/api/tests/batch.test.ts @@ -236,4 +236,198 @@ describe("GET /api/verify/batch/:batchNumber", () => { expect(mockedSupabase.eq).toHaveBeenNthCalledWith(1, "batch_number", "bn2024001"); expect(mockedSupabase.eq).toHaveBeenNthCalledWith(2, "batch_number", "bn2024001"); }); + + it("returns unknown expiry_status when expiry_date is null", async () => { + mockedSupabase.maybeSingle.mockResolvedValueOnce({ + data: { + batch_number: "BN-NULL-EXPIRY", + manufacturing_date: "2026-01-10", + expiry_date: null, + recall_status: "none", + quantity_produced: 5000, + medicine: { + id: "medicine-1", + brand_name: "SahiCure", + generic_name: "Paracetamol", + cdsco_approval_status: "Approved", + is_counterfeit_alert: false, + }, + manufacturer: { + name: "Sahi Pharma Ltd", + license_number: "LIC-12345", + address: "Industrial Area", + city: "Ahmedabad", + state: "Gujarat", + pincode: "380001", + phone: "07912345678", + email: "quality@sahipharma.example", + website: "https://sahipharma.example", + gmp_certified: true, + location: { coordinates: [72.5714, 23.0225] }, + }, + }, + error: null, + }); + + const response = await request(app).get("/api/verify/batch/BN-NULL-EXPIRY"); + + expect(response.status).toBe(200); + expect(response.body.expiry_status).toBe("unknown"); + }); + + it("returns unknown expiry_status for malformed expiry_date", async () => { + mockedSupabase.maybeSingle.mockResolvedValueOnce({ + data: { + batch_number: "BN-BAD-DATE", + manufacturing_date: "2026-01-10", + expiry_date: "not-a-date", + recall_status: "none", + quantity_produced: 5000, + medicine: { + id: "medicine-1", + brand_name: "SahiCure", + generic_name: "Paracetamol", + cdsco_approval_status: "Approved", + is_counterfeit_alert: false, + }, + manufacturer: { + name: "Sahi Pharma Ltd", + license_number: "LIC-12345", + address: "Industrial Area", + city: "Ahmedabad", + state: "Gujarat", + pincode: "380001", + phone: "07912345678", + email: "quality@sahipharma.example", + website: "https://sahipharma.example", + gmp_certified: true, + location: { coordinates: [72.5714, 23.0225] }, + }, + }, + error: null, + }); + + const response = await request(app).get("/api/verify/batch/BN-BAD-DATE"); + + expect(response.status).toBe(200); + expect(response.body.expiry_status).toBe("unknown"); + }); + + it("returns red expiry_status for an expired batch", async () => { + mockedSupabase.maybeSingle.mockResolvedValueOnce({ + data: { + batch_number: "BN-EXPIRED", + manufacturing_date: "2020-01-10", + expiry_date: "2024-01-01", + recall_status: "none", + quantity_produced: 5000, + medicine: { + id: "medicine-1", + brand_name: "SahiCure", + generic_name: "Paracetamol", + cdsco_approval_status: "Approved", + is_counterfeit_alert: false, + }, + manufacturer: { + name: "Sahi Pharma Ltd", + license_number: "LIC-12345", + address: "Industrial Area", + city: "Ahmedabad", + state: "Gujarat", + pincode: "380001", + phone: "07912345678", + email: "quality@sahipharma.example", + website: "https://sahipharma.example", + gmp_certified: true, + location: { coordinates: [72.5714, 23.0225] }, + }, + }, + error: null, + }); + + const response = await request(app).get("/api/verify/batch/BN-EXPIRED"); + + expect(response.status).toBe(200); + expect(response.body.expiry_status).toBe("red"); + }); + + it("returns yellow expiry_status for near-expiry batch (within 6 months)", async () => { + const nearFuture = new Date(); + nearFuture.setMonth(nearFuture.getMonth() + 3); + const nearExpiryDate = nearFuture.toISOString().slice(0, 10); + + mockedSupabase.maybeSingle.mockResolvedValueOnce({ + data: { + batch_number: "BN-NEAR-EXPIRY", + manufacturing_date: "2025-06-01", + expiry_date: nearExpiryDate, + recall_status: "none", + quantity_produced: 5000, + medicine: { + id: "medicine-1", + brand_name: "SahiCure", + generic_name: "Paracetamol", + cdsco_approval_status: "Approved", + is_counterfeit_alert: false, + }, + manufacturer: { + name: "Sahi Pharma Ltd", + license_number: "LIC-12345", + address: "Industrial Area", + city: "Ahmedabad", + state: "Gujarat", + pincode: "380001", + phone: "07912345678", + email: "quality@sahipharma.example", + website: "https://sahipharma.example", + gmp_certified: true, + location: { coordinates: [72.5714, 23.0225] }, + }, + }, + error: null, + }); + + const response = await request(app).get("/api/verify/batch/BN-NEAR-EXPIRY"); + + expect(response.status).toBe(200); + expect(response.body.expiry_status).toBe("yellow"); + }); + + it("returns green expiry_status for a future expiry date", async () => { + mockedSupabase.maybeSingle.mockResolvedValueOnce({ + data: { + batch_number: "BN-FUTURE", + manufacturing_date: "2026-01-10", + expiry_date: "2099-12-31", + recall_status: "none", + quantity_produced: 5000, + medicine: { + id: "medicine-1", + brand_name: "SahiCure", + generic_name: "Paracetamol", + cdsco_approval_status: "Approved", + is_counterfeit_alert: false, + }, + manufacturer: { + name: "Sahi Pharma Ltd", + license_number: "LIC-12345", + address: "Industrial Area", + city: "Ahmedabad", + state: "Gujarat", + pincode: "380001", + phone: "07912345678", + email: "quality@sahipharma.example", + website: "https://sahipharma.example", + gmp_certified: true, + location: { coordinates: [72.5714, 23.0225] }, + }, + }, + error: null, + }); + + const response = await request(app).get("/api/verify/batch/BN-FUTURE"); + + expect(response.status).toBe(200); + expect(response.body.expiry_status).toBe("green"); + }); });