Repository: RSUMMI-PPL-C5/INVENTUM-BE
Pull request #103: Feat/add Maintenance/calibration requests
Author: login: farrelsheva
Created: 2025-04-28T13:41:22Z | Merged: 2025-04-29T06:25:12Z

Adds two API endpoints, for POST requests of maintenance and calibration requests

<!-- This is an auto-generated comment: release notes by coderabbit.ai -->

## Summary by CodeRabbit

- **New Features**
  - Introduced endpoints for creating maintenance and calibration requests, accessible via the `/request` route.
  - Added request validation to ensure required fields are present and correctly formatted.
  - Implemented controllers and services to handle request creation and response with appropriate status and data.

- **Tests**
  - Added comprehensive unit tests for request controllers, services, repositories, and routes to verify correct behavior and error handling.

<!-- end of auto-generated comment: release notes by coderabbit.ai -->


Diff:
diff --git a/__tests__/unit/controllers/request/add-request.controller.unit.test.ts b/__tests__/unit/controllers/request/add-request.controller.unit.test.ts
new file mode 100644
index 0000000..85bfd53
--- /dev/null
+++ b/__tests__/unit/controllers/request/add-request.controller.unit.test.ts
@@ -0,0 +1,126 @@
+import RequestController from "../../../../src/controllers/request.controller";
+import RequestService from "../../../../src/services/request.service";
+import { Request, Response, NextFunction } from "express";
+
+jest.mock("../../../../src/services/request.service");
+
+describe("RequestController", () => {
+  let controller: RequestController;
+  let req: Partial<Request>;
+  let res: Partial<Response>;
+  let next: NextFunction;
+
+  beforeEach(() => {
+    controller = new RequestController();
+    req = {
+      body: {
+        medicalEquipment: "EQ123",
+        complaint: "Equipment not working properly",
+        submissionDate: new Date().toISOString(),
+      },
+      user: { userId: "USER123" },
+    };
+    res = { status: jest.fn().mockReturnThis(), json: jest.fn() };
+    next = jest.fn();
+  });
+
+  describe("createMaintenanceRequest", () => {
+    it("should create maintenance request successfully", async () => {
+      const mockRequest = {
+        id: "REQ123",
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment not working properly",
+        submissionDate: new Date(),
+        status: "Pending",
+        requestType: "MAINTENANCE",
+      };
+
+      (RequestService.prototype.createRequest as jest.Mock).mockResolvedValue(
+        mockRequest,
+      );
+
+      await controller.createMaintenanceRequest(
+        req as Request,
+        res as Response,
+        next,
+      );
+
+      expect(RequestService.prototype.createRequest).toHaveBeenCalledWith({
+        ...req.body,
+        userId: "USER123",
+        createdBy: "USER123",
+        requestType: "MAINTENANCE",
+      });
+      expect(res.status).toHaveBeenCalledWith(201);
+      expect(res.json).toHaveBeenCalledWith({
+        status: "success",
+        data: mockRequest,
+      });
+    });
+
+    it("should call next(error) on exception", async () => {
+      (RequestService.prototype.createRequest as jest.Mock).mockRejectedValue(
+        new Error("Failed to create maintenance request"),
+      );
+
+      await controller.createMaintenanceRequest(
+        req as Request,
+        res as Response,
+        next,
+      );
+
+      expect(next).toHaveBeenCalled();
+    });
+  });
+
+  describe("createCalibrationRequest", () => {
+    it("should create calibration request successfully", async () => {
+      const mockRequest = {
+        id: "REQ123",
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment needs calibration",
+        submissionDate: new Date(),
+        status: "Pending",
+        requestType: "CALIBRATION",
+      };
+
+      (RequestService.prototype.createRequest as jest.Mock).mockResolvedValue(
+        mockRequest,
+      );
+
+      await controller.createCalibrationRequest(
+        req as Request,
+        res as Response,
+        next,
+      );
+
+      expect(RequestService.prototype.createRequest).toHaveBeenCalledWith({
+        ...req.body,
+        userId: "USER123",
+        createdBy: "USER123",
+        requestType: "CALIBRATION",
+      });
+      expect(res.status).toHaveBeenCalledWith(201);
+      expect(res.json).toHaveBeenCalledWith({
+        status: "success",
+        data: mockRequest,
+      });
+    });
+
+    it("should call next(error) on exception", async () => {
+      (RequestService.prototype.createRequest as jest.Mock).mockRejectedValue(
+        new Error("Failed to create calibration request"),
+      );
+
+      await controller.createCalibrationRequest(
+        req as Request,
+        res as Response,
+        next,
+      );
+
+      expect(next).toHaveBeenCalled();
+    });
+  });
+});
diff --git a/__tests__/unit/repository/request/add-request.repository.unit.test.ts b/__tests__/unit/repository/request/add-request.repository.unit.test.ts
new file mode 100644
index 0000000..9884fb6
--- /dev/null
+++ b/__tests__/unit/repository/request/add-request.repository.unit.test.ts
@@ -0,0 +1,128 @@
+import RequestRepository from "../../../../src/repository/request.repository";
+import { getJakartaTime } from "../../../../src/utils/date.utils";
+
+// Mock Prisma Client
+jest.mock("@prisma/client", () => {
+  const mockCreate = jest.fn();
+
+  return {
+    PrismaClient: jest.fn().mockImplementation(() => ({
+      request: {
+        create: mockCreate,
+      },
+    })),
+    __mockPrisma: {
+      create: mockCreate,
+    },
+  };
+});
+
+// Mock getJakartaTime
+jest.mock("../../../../src/utils/date.utils", () => ({
+  getJakartaTime: jest.fn(),
+}));
+
+// Get access to the mocked Prisma functions
+const { __mockPrisma: mockPrisma } = jest.requireMock("@prisma/client");
+
+describe("RequestRepository", () => {
+  let requestRepository: RequestRepository;
+  let mockDate: Date;
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+    requestRepository = new RequestRepository();
+    // Mock the Jakarta time
+    mockDate = new Date();
+    (getJakartaTime as jest.Mock).mockReturnValue(mockDate);
+  });
+
+  describe("createRequest", () => {
+    it("should create a maintenance request successfully", async () => {
+      const requestData = {
+        id: "REQ123",
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment not working properly",
+        submissionDate: new Date(),
+        status: "Pending",
+        createdBy: "USER123",
+        requestType: "MAINTENANCE",
+      };
+
+      const expectedResponse = {
+        ...requestData,
+        createdOn: mockDate,
+        modifiedOn: mockDate,
+      };
+
+      (mockPrisma.create as jest.Mock).mockResolvedValue(expectedResponse);
+
+      const result = await requestRepository.createRequest(requestData);
+
+      expect(mockPrisma.create).toHaveBeenCalledWith({
+        data: {
+          ...requestData,
+          createdOn: mockDate,
+          modifiedOn: mockDate,
+        },
+      });
+      expect(result).toEqual(expectedResponse);
+    });
+
+    it("should create a calibration request successfully", async () => {
+      const requestData = {
+        id: "REQ123",
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment needs calibration",
+        submissionDate: new Date(),
+        status: "Pending",
+        createdBy: "USER123",
+        requestType: "CALIBRATION",
+      };
+
+      const expectedResponse = {
+        ...requestData,
+        createdOn: mockDate,
+        modifiedOn: mockDate,
+      };
+
+      (mockPrisma.create as jest.Mock).mockResolvedValue(expectedResponse);
+
+      const result = await requestRepository.createRequest(requestData);
+
+      expect(mockPrisma.create).toHaveBeenCalledWith({
+        data: {
+          ...requestData,
+          createdOn: mockDate,
+          modifiedOn: mockDate,
+        },
+      });
+      expect(result).toEqual(expectedResponse);
+    });
+
+    it("should throw an error if request creation fails", async () => {
+      const requestData = {
+        id: "REQ123",
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment not working properly",
+        submissionDate: new Date(),
+        status: "Pending",
+        createdBy: "USER123",
+        requestType: "MAINTENANCE",
+      };
+
+      const errorMessage = "Request creation failed";
+      (mockPrisma.create as jest.Mock).mockRejectedValue(
+        new Error(errorMessage),
+      );
+
+      await expect(
+        requestRepository.createRequest(requestData),
+      ).rejects.toThrow(errorMessage);
+      expect(mockPrisma.create).toHaveBeenCalledTimes(1);
+    });
+  });
+});
diff --git a/__tests__/unit/routes/request/request.route.unit.test.ts b/__tests__/unit/routes/request/request.route.unit.test.ts
new file mode 100644
index 0000000..ed3121f
--- /dev/null
+++ b/__tests__/unit/routes/request/request.route.unit.test.ts
@@ -0,0 +1,67 @@
+import { Router } from "express";
+
+// Mock express.Router
+jest.mock("express", () => {
+  const mockRouter = {
+    use: jest.fn().mockReturnThis(),
+    post: jest.fn().mockReturnThis(),
+  };
+  return {
+    Router: jest.fn(() => mockRouter),
+  };
+});
+
+// Mock controller
+jest.mock("../../../../src/controllers/request.controller", () => {
+  return jest.fn().mockImplementation(() => ({
+    createMaintenanceRequest: jest.fn(),
+    createCalibrationRequest: jest.fn(),
+  }));
+});
+
+// Mock middleware with explicit any types and unused args as _
+jest.mock("../../../../src/middleware/verifyToken", () =>
+  jest.fn((_req: any, _res: any, next: any) => next()),
+);
+
+jest.mock("../../../../src/validations/request.validation", () => ({
+  createRequestValidation: jest.fn((_req: any, _res: any, next: any) => next()),
+}));
+
+jest.mock("../../../../src/middleware/validateRequest", () => ({
+  validateRequest: jest.fn((_req: any, _res: any, next: any) => next()),
+}));
+
+// Import the route after all mocks
+import "../../../../src/routes/request.route";
+
+describe("Request Routes", () => {
+  it("should create router with Router()", () => {
+    expect(Router).toHaveBeenCalled();
+  });
+
+  it("should use verifyToken middleware", () => {
+    const mockRouter = (Router as jest.Mock).mock.results[0].value;
+    expect(mockRouter.use).toHaveBeenCalledWith(expect.any(Function));
+  });
+
+  it("should register POST /maintenance route with validation", () => {
+    const mockRouter = (Router as jest.Mock).mock.results[0].value;
+    expect(mockRouter.post).toHaveBeenCalledWith(
+      "/maintenance",
+      expect.any(Function),
+      expect.any(Function),
+      expect.any(Function),
+    );
+  });
+
+  it("should register POST /calibration route with validation", () => {
+    const mockRouter = (Router as jest.Mock).mock.results[0].value;
+    expect(mockRouter.post).toHaveBeenCalledWith(
+      "/calibration",
+      expect.any(Function),
+      expect.any(Function),
+      expect.any(Function),
+    );
+  });
+});
diff --git a/__tests__/unit/services/request/add-request.service.unit.test.ts b/__tests__/unit/services/request/add-request.service.unit.test.ts
new file mode 100644
index 0000000..c4b39f5
--- /dev/null
+++ b/__tests__/unit/services/request/add-request.service.unit.test.ts
@@ -0,0 +1,101 @@
+import { v4 as uuidv4 } from "uuid";
+import RequestService from "../../../../src/services/request.service";
+import RequestRepository from "../../../../src/repository/request.repository";
+
+jest.mock("../../../../src/repository/request.repository");
+jest.mock("uuid");
+
+describe("RequestService", () => {
+  let requestService: RequestService;
+  let mockRequestRepository: jest.Mocked<RequestRepository>;
+
+  beforeEach(() => {
+    jest.clearAllMocks();
+    mockRequestRepository =
+      new RequestRepository() as jest.Mocked<RequestRepository>;
+    requestService = new RequestService();
+    (requestService as any).requestRepository = mockRequestRepository;
+
+    // Default mock for uuid
+    (uuidv4 as jest.Mock).mockReturnValue("generated-uuid");
+  });
+
+  describe("createRequest", () => {
+    it("should create a maintenance request successfully", async () => {
+      const mockRequestData = {
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment not working properly",
+        submissionDate: new Date(),
+        createdBy: "USER123",
+        requestType: "MAINTENANCE" as const,
+      };
+
+      const mockCreatedRequest = {
+        id: "generated-uuid",
+        ...mockRequestData,
+        status: "Pending",
+        createdOn: new Date(),
+      };
+
+      mockRequestRepository.createRequest.mockResolvedValue(mockCreatedRequest);
+
+      const result = await requestService.createRequest(mockRequestData);
+
+      expect(mockRequestRepository.createRequest).toHaveBeenCalledWith({
+        ...mockRequestData,
+        id: "generated-uuid",
+        status: "Pending",
+      });
+      expect(result).toEqual(mockCreatedRequest);
+    });
+
+    it("should create a calibration request successfully", async () => {
+      const mockRequestData = {
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment needs calibration",
+        submissionDate: new Date(),
+        createdBy: "USER123",
+        requestType: "CALIBRATION" as const,
+      };
+
+      const mockCreatedRequest = {
+        id: "generated-uuid",
+        ...mockRequestData,
+        status: "Pending",
+        createdOn: new Date(),
+      };
+
+      mockRequestRepository.createRequest.mockResolvedValue(mockCreatedRequest);
+
+      const result = await requestService.createRequest(mockRequestData);
+
+      expect(mockRequestRepository.createRequest).toHaveBeenCalledWith({
+        ...mockRequestData,
+        id: "generated-uuid",
+        status: "Pending",
+      });
+      expect(result).toEqual(mockCreatedRequest);
+    });
+
+    it("should throw an error if creation fails", async () => {
+      const mockRequestData = {
+        userId: "USER123",
+        medicalEquipment: "EQ123",
+        complaint: "Equipment not working properly",
+        submissionDate: new Date(),
+        createdBy: "USER123",
+        requestType: "MAINTENANCE" as const,
+      };
+
+      mockRequestRepository.createRequest.mockRejectedValue(
+        new Error("Failed to create request"),
+      );
+
+      await expect(
+        requestService.createRequest(mockRequestData),
+      ).rejects.toThrow("Failed to create request");
+    });
+  });
+});
diff --git a/src/controllers/request.controller.ts b/src/controllers/request.controller.ts
new file mode 100644
index 0000000..1644a7c
--- /dev/null
+++ b/src/controllers/request.controller.ts
@@ -0,0 +1,65 @@
+import { Request, Response, NextFunction } from "express";
+import RequestService from "../services/request.service";
+import { CreateRequestDTO } from "../dto/request.dto";
+
+class RequestController {
+  private readonly requestService: RequestService;
+
+  constructor() {
+    this.requestService = new RequestService();
+  }
+
+  public createMaintenanceRequest = async (
+    req: Request,
+    res: Response,
+    next: NextFunction,
+  ): Promise<void> => {
+    try {
+      const userId = (req.user as any).userId;
+
+      const requestData: CreateRequestDTO = {
+        ...req.body,
+        userId,
+        createdBy: userId,
+        requestType: "MAINTENANCE",
+      };
+
+      const result = await this.requestService.createRequest(requestData);
+
+      res.status(201).json({
+        status: "success",
+        data: result,
+      });
+    } catch (error) {
+      next(error);
+    }
+  };
+
+  public createCalibrationRequest = async (
+    req: Request,
+    res: Response,
+    next: NextFunction,
+  ): Promise<void> => {
+    try {
+      const userId = (req.user as any).userId;
+
+      const requestData: CreateRequestDTO = {
+        ...req.body,
+        userId,
+        createdBy: userId,
+        requestType: "CALIBRATION",
+      };
+
+      const result = await this.requestService.createRequest(requestData);
+
+      res.status(201).json({
+        status: "success",
+        data: result,
+      });
+    } catch (error) {
+      next(error);
+    }
+  };
+}
+
+export default RequestController;
diff --git a/src/dto/request.dto.ts b/src/dto/request.dto.ts
new file mode 100644
index 0000000..7908604
--- /dev/null
+++ b/src/dto/request.dto.ts
@@ -0,0 +1,22 @@
+import { Request } from "@prisma/client";
+
+export interface RequesDTO extends Request {}
+
+export interface CreateRequestDTO {
+  userId: string;
+  medicalEquipment: string;
+  complaint?: string;
+  submissionDate: Date;
+  createdBy: string;
+  requestType: "MAINTENANCE" | "CALIBRATION";
+}
+
+export interface RequestResponseDTO {
+  id: string;
+  userID: string;
+  medicalEquipment: string;
+  complaint?: string;
+  submissionDate: Date;
+  status: string;
+  requestType: string;
+}
diff --git a/src/index.ts b/src/index.ts
index 162a66f..2550fe6 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -22,6 +22,7 @@ import userRoutes from "./routes/user.route";
 import authRoutes from "./routes/auth.route";
 import sparepartRoutes from "./routes/sparepart.route";
 import divisionRoutes from "./routes/division.route";
+import requestRoutes from "./routes/request.route";
 import medicalequipmentRoutes from "./routes/medical-equipment.route";
 import maintenanceHistoryRoutes from "./routes/maintenance-history.route";
 import calibrationHistoryRoutes from "./routes/calibration-history.routes";
@@ -105,6 +106,7 @@ app.use("/auth", authRoutes);
 app.use("/user", userRoutes);
 app.use("/spareparts", sparepartRoutes);
 app.use("/divisi", divisionRoutes);
+app.use("/request", requestRoutes);
 app.use("/medical-equipment", [
   medicalequipmentRoutes,
   maintenanceHistoryRoutes,
diff --git a/src/repository/request.repository.ts b/src/repository/request.repository.ts
new file mode 100644
index 0000000..e8710be
--- /dev/null
+++ b/src/repository/request.repository.ts
@@ -0,0 +1,24 @@
+import { PrismaClient } from "@prisma/client";
+import prisma from "../configs/db.config";
+import { getJakartaTime } from "../utils/date.utils";
+
+class RequestRepository {
+  private readonly prisma: PrismaClient;
+
+  constructor() {
+    this.prisma = prisma;
+  }
+
+  public async createRequest(requestData: any): Promise<any> {
+    const jakartaTime = getJakartaTime();
+    return await this.prisma.request.create({
+      data: {
+        ...requestData,
+        createdOn: jakartaTime,
+        modifiedOn: jakartaTime,
+      },
+    });
+  }
+}
+
+export default RequestRepository;
diff --git a/src/routes/request.route.ts b/src/routes/request.route.ts
new file mode 100644
index 0000000..cdbd374
--- /dev/null
+++ b/src/routes/request.route.ts
@@ -0,0 +1,27 @@
+import { Router } from "express";
+import RequestController from "../controllers/request.controller";
+import verifyToken from "../middleware/verifyToken";
+import { validateRequest } from "../middleware/validateRequest";
+import { createRequestValidation } from "../validations/request.validation";
+
+const router = Router();
+const controller = new RequestController();
+
+// Middleware
+router.use(verifyToken);
+
+router.post(
+  "/maintenance",
+  createRequestValidation,
+  validateRequest,
+  controller.createMaintenanceRequest,
+);
+
+router.post(
+  "/calibration",
+  createRequestValidation,
+  validateRequest,
+  controller.createCalibrationRequest,
+);
+
+export default router;
diff --git a/src/services/interface/request.service.interface.ts b/src/services/interface/request.service.interface.ts
new file mode 100644
index 0000000..39191c3
--- /dev/null
+++ b/src/services/interface/request.service.interface.ts
@@ -0,0 +1,5 @@
+import { CreateRequestDTO, RequestResponseDTO } from "../../dto/request.dto";
+
+export interface IRequestService {
+  createRequest(requestData: CreateRequestDTO): Promise<RequestResponseDTO>;
+}
diff --git a/src/services/request.service.ts b/src/services/request.service.ts
new file mode 100644
index 0000000..d293d3b
--- /dev/null
+++ b/src/services/request.service.ts
@@ -0,0 +1,30 @@
+import { v4 as uuidv4 } from "uuid";
+import { IRequestService } from "./interface/request.service.interface";
+import { CreateRequestDTO, RequestResponseDTO } from "../dto/request.dto";
+import RequestRepository from "../repository/request.repository";
+
+class RequestService implements IRequestService {
+  private readonly requestRepository: RequestRepository;
+
+  constructor() {
+    this.requestRepository = new RequestRepository();
+  }
+
+  public async createRequest(
+    requestData: CreateRequestDTO,
+  ): Promise<RequestResponseDTO> {
+    try {
+      const result = await this.requestRepository.createRequest({
+        id: uuidv4(),
+        ...requestData,
+        status: "Pending",
+      });
+
+      return result;
+    } catch (error) {
+      throw error;
+    }
+  }
+}
+
+export default RequestService;
diff --git a/src/validations/request.validation.ts b/src/validations/request.validation.ts
new file mode 100644
index 0000000..6e61a7d
--- /dev/null
+++ b/src/validations/request.validation.ts
@@ -0,0 +1,18 @@
+import { body } from "express-validator";
+
+export const createRequestValidation = [
+  body("medicalEquipment")
+    .notEmpty()
+    .withMessage("Medical equipment ID is required"),
+
+  body("complaint")
+    .optional()
+    .isString()
+    .withMessage("Complaint must be a string"),
+
+  body("submissionDate")
+    .notEmpty()
+    .withMessage("Submission date is required")
+    .isISO8601()
+    .withMessage("Submission date must be a valid date"),
+];


Reviews:
user: login: coderabbitai[bot]
body: **Actionable comments posted: 4**

<details>
<summary>♻️ Duplicate comments (1)</summary><blockquote>

<details>
<summary>src/controllers/request.controller.ts (1)</summary><blockquote>

`38-62`: **Same type safety and duplication issues as in createMaintenanceRequest.**

This method has the same type safety issues and duplication as identified in the `createMaintenanceRequest` method. Apply the same refactoring solution to reduce code duplication and improve type safety.

</blockquote></details>

</blockquote></details>

<details>
<summary>🧹 Nitpick comments (10)</summary><blockquote>

<details>
<summary>src/routes/request.route.ts (1)</summary><blockquote>

`1-8`: **Consider dependency injection for controller**

The controller is instantiated directly in the route file which could make unit testing more difficult. Consider using dependency injection to improve testability.


```diff
import { Router } from "express";
import RequestController from "../controllers/request.controller";
import verifyToken from "../middleware/verifyToken";
import { validateRequest } from "../middleware/validateRequest";
import { createRequestValidation } from "../validations/request.validation";

+// Accept injected controller or create a new instance
+export const createRequestRouter = (controllerInstance?: RequestController) => {
+  const router = Router();
+  const controller = controllerInstance || new RequestController();

-const router = Router();
-const controller = new RequestController();

  // Middleware
  router.use(verifyToken);
  
  // Routes would go here...
  
  return router;
+};

+// For backward compatibility
+const router = createRequestRouter();
+export default router;
```

</blockquote></details>
<details>
<summary>src/services/request.service.ts (1)</summary><blockquote>

`6-12`: **Consider using dependency injection for repository**

The repository is instantiated directly in the constructor, which tightly couples the service to a specific repository implementation and makes unit testing more difficult.


```diff
class RequestService implements IRequestService {
  private readonly requestRepository: RequestRepository;

  constructor() {
-   this.requestRepository = new RequestRepository();
+   // No change in the constructor overload 
  }
  
+ constructor(repository?: RequestRepository) {
+   this.requestRepository = repository || new RequestRepository();
+ }

  // Rest of the class...
}
```

</blockquote></details>
<details>
<summary>__tests__/unit/repository/request/add-request.repository.unit.test.ts (1)</summary><blockquote>

`73-103`: **Duplicate test for calibration request**

This test is nearly identical to the maintenance request test, with the only difference being the `requestType` value. Consider parameterizing this test to reduce duplication.


```diff
- it("should create a calibration request successfully", async () => {
-   const requestData = {
-     id: "REQ123",
-     userId: "USER123",
-     medicalEquipment: "EQ123",
-     complaint: "Equipment needs calibration",
-     submissionDate: new Date(),
-     status: "Pending",
-     createdBy: "USER123",
-     requestType: "CALIBRATION",
-   };
-
-   const expectedResponse = {
-     ...requestData,
-     createdOn: mockDate,
-     modifiedOn: mockDate,
-   };
-
-   (mockPrisma.create as jest.Mock).mockResolvedValue(expectedResponse);
-
-   const result = await requestRepository.createRequest(requestData);
-
-   expect(mockPrisma.create).toHaveBeenCalledWith({
-     data: {
-       ...requestData,
-       createdOn: mockDate,
-       modifiedOn: mockDate,
-     },
-   });
-   expect(result).toEqual(expectedResponse);
- });

+ it.each([
+   ["MAINTENANCE", "Equipment not working properly"],
+   ["CALIBRATION", "Equipment needs calibration"]
+ ])("should create a %s request successfully", async (requestType, complaint) => {
+   const requestData = {
+     id: "REQ123",
+     userId: "USER123",
+     medicalEquipment: "EQ123",
+     complaint,
+     submissionDate: new Date(),
+     status: "Pending",
+     createdBy: "USER123",
+     requestType,
+   };
+
+   const expectedResponse = {
+     ...requestData,
+     createdOn: mockDate,
+     modifiedOn: mockDate,
+   };
+
+   (mockPrisma.create as jest.Mock).mockResolvedValue(expectedResponse);
+
+   const result = await requestRepository.createRequest(requestData);
+
+   expect(mockPrisma.create).toHaveBeenCalledWith({
+     data: {
+       ...requestData,
+       createdOn: mockDate,
+       modifiedOn: mockDate,
+     },
+   });
+   expect(result).toEqual(expectedResponse);
+ });
```

</blockquote></details>
<details>
<summary>__tests__/unit/services/request/add-request.service.unit.test.ts (3)</summary><blockquote>

`12-21`: **Access of repository property could be improved.**

The test setup is directly accessing `requestRepository` through type casting:
```typescript
(requestService as any).requestRepository = mockRequestRepository;
```

This suggests a private property access. Consider enhancing the `RequestService` class to allow dependency injection through its constructor, which would make testing cleaner and reduce the need for type casting.

---

`53-80`: **Consider using parametrized tests to reduce duplication.**

This test case is nearly identical to the maintenance request test, with only the request type being different. Consider using Jest's parametrized tests to reduce code duplication:

```diff
-  it("should create a maintenance request successfully", async () => {
-    const mockRequestData = {
-      userId: "USER123",
-      medicalEquipment: "EQ123",
-      complaint: "Equipment not working properly",
-      submissionDate: new Date(),
-      createdBy: "USER123",
-      requestType: "MAINTENANCE" as const,
-    };
-    // ... rest of test
-  });
-
-  it("should create a calibration request successfully", async () => {
-    const mockRequestData = {
-      userId: "USER123",
-      medicalEquipment: "EQ123",
-      complaint: "Equipment needs calibration",
-      submissionDate: new Date(),
-      createdBy: "USER123",
-      requestType: "CALIBRATION" as const,
-    };
-    // ... rest of test
-  });
+  test.each([
+    {
+      requestType: "MAINTENANCE" as const,
+      complaint: "Equipment not working properly",
+      testName: "maintenance request"
+    },
+    {
+      requestType: "CALIBRATION" as const,
+      complaint: "Equipment needs calibration",
+      testName: "calibration request"
+    }
+  ])("should create a $testName successfully", async ({ requestType, complaint }) => {
+    const mockRequestData = {
+      userId: "USER123",
+      medicalEquipment: "EQ123",
+      complaint,
+      submissionDate: new Date(),
+      createdBy: "USER123",
+      requestType,
+    };
+    // ... rest of test
+  });
```

---

`82-99`: **Verify repository call in error test case.**

While the error test correctly verifies that the service propagates repository errors, it should also verify that the repository's `createRequest` method was called with the expected arguments before throwing:

```diff
  it("should throw an error if creation fails", async () => {
    const mockRequestData = {
      userId: "USER123",
      medicalEquipment: "EQ123",
      complaint: "Equipment not working properly",
      submissionDate: new Date(),
      createdBy: "USER123",
      requestType: "MAINTENANCE" as const,
    };

    mockRequestRepository.createRequest.mockRejectedValue(
      new Error("Failed to create request"),
    );

    await expect(
      requestService.createRequest(mockRequestData),
    ).rejects.toThrow("Failed to create request");
+   
+   expect(mockRequestRepository.createRequest).toHaveBeenCalledWith({
+     ...mockRequestData,
+     id: "generated-uuid",
+     status: "Pending",
+   });
  });
```

</blockquote></details>
<details>
<summary>src/controllers/request.controller.ts (2)</summary><blockquote>

`5-10`: **Implement dependency injection for better testability.**

The controller directly instantiates the `RequestService` in its constructor, creating tight coupling. Consider using dependency injection instead:

```diff
class RequestController {
  private readonly requestService: RequestService;

-  constructor() {
-    this.requestService = new RequestService();
+  constructor(requestService?: RequestService) {
+    this.requestService = requestService || new RequestService();
  }
```

This allows for easier testing by injecting mock services while maintaining backward compatibility.

---

`12-36`: **Improve type safety for user extraction and consider refactoring to reduce duplication.**

The controller casts `req.user` to `any` to access `userId`, which is not type-safe:

```typescript
const userId = (req.user as any).userId;
```

Consider defining an extended Express request interface that includes the user property with the correct type.

Additionally, this method has significant duplication with `createCalibrationRequest`. Consider refactoring to use a single method with the request type as a parameter.


```diff
+interface AuthenticatedRequest extends Request {
+  user: {
+    userId: string;
+    [key: string]: any;
+  };
+}

+private createGenericRequest = async (
+  req: AuthenticatedRequest,
+  res: Response,
+  next: NextFunction,
+  requestType: "MAINTENANCE" | "CALIBRATION"
+): Promise<void> => {
+  try {
+    const userId = req.user.userId;
+
+    const requestData: CreateRequestDTO = {
+      ...req.body,
+      userId,
+      createdBy: userId,
+      requestType,
+    };
+
+    const result = await this.requestService.createRequest(requestData);
+
+    res.status(201).json({
+      status: "success",
+      data: result,
+    });
+  } catch (error) {
+    next(error);
+  }
+};

public createMaintenanceRequest = async (
-  req: Request,
+  req: AuthenticatedRequest,
  res: Response,
  next: NextFunction,
): Promise<void> => {
-  try {
-    const userId = (req.user as any).userId;
-
-    const requestData: CreateRequestDTO = {
-      ...req.body,
-      userId,
-      createdBy: userId,
-      requestType: "MAINTENANCE",
-    };
-
-    const result = await this.requestService.createRequest(requestData);
-
-    res.status(201).json({
-      status: "success",
-      data: result,
-    });
-  } catch (error) {
-    next(error);
-  }
+  return this.createGenericRequest(req, res, next, "MAINTENANCE");
};
```

</blockquote></details>
<details>
<summary>__tests__/unit/routes/request/request.route.unit.test.ts (1)</summary><blockquote>

`38-66`: **Make route tests more specific about middleware order and identity.**

The tests verify that routes are registered with "some function" but don't verify the specific middleware or their order. Consider enhancing the tests to verify the exact middleware functions used for each route:

```diff
  it("should register POST /maintenance route with validation", () => {
    const mockRouter = (Router as jest.Mock).mock.results[0].value;
+   
+   // Import the actual middleware functions for comparison
+   const { createRequestValidation } = require("../../../../src/validations/request.validation");
+   const { validateRequest } = require("../../../../src/middleware/validateRequest");
+   const controller = require("../../../../src/controllers/request.controller").mock.instances[0];
+   
    expect(mockRouter.post).toHaveBeenCalledWith(
      "/maintenance",
-     expect.any(Function),
-     expect.any(Function),
-     expect.any(Function),
+     createRequestValidation,
+     validateRequest,
+     controller.createMaintenanceRequest,
    );
  });
```

Apply a similar improvement to the `/calibration` route test.

</blockquote></details>
<details>
<summary>src/dto/request.dto.ts (1)</summary><blockquote>

`3-3`: **Fix typo in interface name and review necessity.**

There's a typo in the interface name (`RequesDTO` should be `RequestDTO`). Additionally, this interface doesn't add any properties to the extended `Request` type, making it potentially unnecessary if it's not being used elsewhere.

```diff
-export interface RequesDTO extends Request {}
+export interface RequestDTO extends Request {}
```

Consider removing this interface if it's not being utilized elsewhere in the codebase.

</blockquote></details>

</blockquote></details>

<details>
<summary>📜 Review details</summary>

**Configuration used: CodeRabbit UI**
**Review profile: CHILL**
**Plan: Pro**

<details>
<summary>📥 Commits</summary>

Reviewing files that changed from the base of the PR and between f7f0ad4ea0aa8fa3cf7df304fdcc138a32ca952f and a345db48aca18a00f51cc7eeea188331aab041fc.

</details>

<details>
<summary>📒 Files selected for processing (12)</summary>

* `__tests__/unit/controllers/request/add-request.controller.unit.test.ts` (1 hunks)
* `__tests__/unit/repository/request/add-request.repository.unit.test.ts` (1 hunks)
* `__tests__/unit/routes/request/request.route.unit.test.ts` (1 hunks)
* `__tests__/unit/services/request/add-request.service.unit.test.ts` (1 hunks)
* `src/controllers/request.controller.ts` (1 hunks)
* `src/dto/request.dto.ts` (1 hunks)
* `src/index.ts` (2 hunks)
* `src/repository/request.repository.ts` (1 hunks)
* `src/routes/request.route.ts` (1 hunks)
* `src/services/interface/request.service.interface.ts` (1 hunks)
* `src/services/request.service.ts` (1 hunks)
* `src/validations/request.validation.ts` (1 hunks)

</details>

<details>
<summary>🧰 Additional context used</summary>

<details>
<summary>🧬 Code Graph Analysis (6)</summary>

<details>
<summary>src/services/interface/request.service.interface.ts (1)</summary><blockquote>

<details>
<summary>src/dto/request.dto.ts (2)</summary>

* `CreateRequestDTO` (5-12)
* `RequestResponseDTO` (14-22)

</details>

</blockquote></details>
<details>
<summary>__tests__/unit/repository/request/add-request.repository.unit.test.ts (1)</summary><blockquote>

<details>
<summary>src/utils/date.utils.ts (1)</summary>

* `getJakartaTime` (5-8)

</details>

</blockquote></details>
<details>
<summary>src/routes/request.route.ts (2)</summary><blockquote>

<details>
<summary>src/validations/request.validation.ts (1)</summary>

* `createRequestValidation` (3-18)

</details>
<details>
<summary>src/middleware/validateRequest.ts (1)</summary>

* `validateRequest` (4-22)

</details>

</blockquote></details>
<details>
<summary>src/services/request.service.ts (2)</summary><blockquote>

<details>
<summary>src/services/interface/request.service.interface.ts (1)</summary>

* `IRequestService` (3-5)

</details>
<details>
<summary>src/dto/request.dto.ts (2)</summary>

* `CreateRequestDTO` (5-12)
* `RequestResponseDTO` (14-22)

</details>

</blockquote></details>
<details>
<summary>src/repository/request.repository.ts (1)</summary><blockquote>

<details>
<summary>src/utils/date.utils.ts (1)</summary>

* `getJakartaTime` (5-8)

</details>

</blockquote></details>
<details>
<summary>src/controllers/request.controller.ts (1)</summary><blockquote>

<details>
<summary>src/dto/request.dto.ts (1)</summary>

* `CreateRequestDTO` (5-12)

</details>

</blockquote></details>

</details><details>
<summary>🪛 Biome (1.9.4)</summary>

<details>
<summary>src/services/request.service.ts</summary>

[error] 25-25: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.


(lint/complexity/noUselessCatch)

</details>

</details>

</details>

<details>
<summary>⏰ Context from checks skipped due to timeout of 90000ms (1)</summary>

* GitHub Check: sonarqube

</details>

<details>
<summary>🔇 Additional comments (17)</summary><blockquote>

<details>
<summary>src/index.ts (2)</summary>

`25-25`: **Clean integration of the new request routes module.**

The import follows the consistent pattern used for other route modules in the application.

---

`108-108`: **Proper registration of request routes.**

The route registration is correctly placed among other API route registrations, using the appropriate path prefix "/request" which aligns with the feature purpose.

</details>
<details>
<summary>src/services/interface/request.service.interface.ts (1)</summary>

`1-5`: **Well-defined service interface with proper typing.**

The interface properly establishes a clean contract for request creation with strong typing through DTOs. It follows good practices by clearly separating the interface from implementation and using appropriate Promise typing for async operations.

</details>
<details>
<summary>src/routes/request.route.ts (3)</summary>

`7-11`: **Middleware application looks good**

The router correctly applies the `verifyToken` middleware to protect all request routes, ensuring only authenticated users can access them.

---

`13-18`: **Endpoint setup for maintenance requests looks correct**

The maintenance request endpoint is properly configured with validation middleware and mapped to the correct controller method. The validation chain helps ensure data integrity before processing the request.

---

`20-25`: **Endpoint setup for calibration requests looks correct**

The calibration request endpoint is properly configured with validation middleware and mapped to the correct controller method, mirroring the maintenance endpoint pattern.

</details>
<details>
<summary>__tests__/unit/controllers/request/add-request.controller.unit.test.ts (4)</summary>

`15-22`: **Good test setup with mock request data**

The test setup correctly initializes the mock request with all necessary properties including medical equipment ID, complaint, submission date, and user information.

---

`27-60`: **Comprehensive test for maintenance request creation**

The test for `createMaintenanceRequest` is thorough, verifying:
1. Service method is called with correct parameters
2. Response status code is 201 (Created)
3. Response JSON structure includes success status and created request data

All key aspects of the controller function are properly tested.

---

`62-74`: **Error handling test is complete**

The test properly verifies that when the service throws an error, the controller passes it to the next middleware function, which follows Express error handling best practices.

---

`77-124`: **Tests for calibration request mirror maintenance request tests**

The tests for the calibration request properly mirror the maintenance request tests, with appropriate changes for the request type. This ensures consistent behavior between both endpoints.

</details>
<details>
<summary>src/services/request.service.ts (1)</summary>

`13-24`: **The createRequest method looks good**

The method correctly implements the interface, generates a UUID for the request ID, sets the initial status to "Pending", and delegates to the repository.

</details>
<details>
<summary>__tests__/unit/repository/request/add-request.repository.unit.test.ts (4)</summary>

`4-18`: **Good Prisma client mocking approach**

The Prisma client is mocked effectively, exposing the mock create function through a custom property for assertions. This is a clean approach to mocking the ORM.

---

`20-23`: **Proper mocking of utility function**

The `getJakartaTime` function is correctly mocked to allow controlled testing of timestamp creation.

---

`40-71`: **Comprehensive test for maintenance request creation**

The test for creating a maintenance request thoroughly verifies:
1. Repository correctly calls Prisma with all request data
2. Timestamp fields are populated correctly
3. Repository returns the expected response

All key aspects of the repository function are properly tested.

---

`105-126`: **Error handling test is complete**

The test for error propagation from Prisma is well-implemented, verifying that errors from the database layer are properly propagated through the repository layer.

</details>
<details>
<summary>__tests__/unit/services/request/add-request.service.unit.test.ts (1)</summary>

`23-51`: **Test case properly validates maintenance request creation.**

The test properly verifies that the service is creating a maintenance request with the expected data and returning the correct response.

</details>
<details>
<summary>src/dto/request.dto.ts (1)</summary>

`5-12`: **CreateRequestDTO looks good and properly typed.**

The interface defines all necessary fields for creating a request with appropriate types, including the constrained union type for `requestType`.

</details>

</blockquote></details>

</details>

<!-- This is an auto-generated comment by CodeRabbit for review status -->
state: COMMENTED
author_association: NONE
submitted_at: 2025-04-28T13:50:32Z

Review comments:
diff_hunk: @@ -0,0 +1,24 @@
+import { PrismaClient } from "@prisma/client";
+import prisma from "../configs/db.config";
+import { getJakartaTime } from "../utils/date.utils";
+
+class RequestRepository {
+  private readonly prisma: PrismaClient;
+
+  constructor() {
+    this.prisma = prisma;
+  }
+
+  public async createRequest(requestData: any): Promise<any> {
+    const jakartaTime = getJakartaTime();
+    return await this.prisma.request.create({
+      data: {
+        ...requestData,
+        createdOn: jakartaTime,
+        modifiedOn: jakartaTime,
+      },
+    });
+  }
path: src/repository/request.repository.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Improve type safety by replacing `any` with specific types.**

The method currently uses `any` types, which bypasses TypeScript's type checking. Consider using the appropriate DTOs to improve type safety and maintainability.

```diff
-  public async createRequest(requestData: any): Promise<any> {
+  public async createRequest(requestData: Omit<CreateRequestDTO, 'requestType'>): Promise<RequestResponseDTO> {
```

Additionally, consider adding error handling for database operations:

```diff
   public async createRequest(requestData: Omit<CreateRequestDTO, 'requestType'>): Promise<RequestResponseDTO> {
     const jakartaTime = getJakartaTime();
-    return await this.prisma.request.create({
-      data: {
-        ...requestData,
-        createdOn: jakartaTime,
-        modifiedOn: jakartaTime,
-      },
-    });
+    try {
+      return await this.prisma.request.create({
+        data: {
+          ...requestData,
+          createdOn: jakartaTime,
+          modifiedOn: jakartaTime,
+        },
+      });
+    } catch (error) {
+      console.error('Error creating request:', error);
+      throw error;
+    }
   }
```

Don't forget to import the necessary types:

```diff
import { PrismaClient } from "@prisma/client";
import prisma from "../configs/db.config";
import { getJakartaTime } from "../utils/date.utils";
+import { CreateRequestDTO, RequestResponseDTO } from "../dto/request.dto";
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
// src/repository/request.repository.ts

import { PrismaClient } from "@prisma/client";
import prisma from "../configs/db.config";
import { getJakartaTime } from "../utils/date.utils";
import { CreateRequestDTO, RequestResponseDTO } from "../dto/request.dto";

export class RequestRepository {
  private prisma: PrismaClient = prisma;

  public async createRequest(
    requestData: Omit<CreateRequestDTO, 'requestType'>
  ): Promise<RequestResponseDTO> {
    const jakartaTime = getJakartaTime();
    try {
      return await this.prisma.request.create({
        data: {
          ...requestData,
          createdOn: jakartaTime,
          modifiedOn: jakartaTime,
        },
      });
    } catch (error) {
      console.error('Error creating request:', error);
      throw error;
    }
  }
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-28T13:50:31Z
author_association: NONE
diff_hunk: @@ -0,0 +1,18 @@
+import { body } from "express-validator";
+
+export const createRequestValidation = [
+  body("medicalEquipment")
+    .notEmpty()
+    .withMessage("Medical equipment ID is required"),
+
+  body("complaint")
+    .optional()
+    .isString()
+    .withMessage("Complaint must be a string"),
+
+  body("submissionDate")
+    .notEmpty()
+    .withMessage("Submission date is required")
+    .isISO8601()
+    .withMessage("Submission date must be a valid date"),
+];
path: src/validations/request.validation.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Add validation for missing required fields.**

The current validation rules don't cover all required fields from the CreateRequestDTO. Based on the DTO definition, these additional validations are needed:

```diff
export const createRequestValidation = [
  body("medicalEquipment")
    .notEmpty()
    .withMessage("Medical equipment ID is required"),

  body("complaint")
    .optional()
    .isString()
    .withMessage("Complaint must be a string"),

  body("submissionDate")
    .notEmpty()
    .withMessage("Submission date is required")
    .isISO8601()
    .withMessage("Submission date must be a valid date"),
+
+  body("userId")
+    .notEmpty()
+    .withMessage("User ID is required"),
+
+  body("createdBy")
+    .notEmpty()
+    .withMessage("Created by is required"),
+
+  body("requestType")
+    .notEmpty()
+    .withMessage("Request type is required")
+    .isIn(["MAINTENANCE", "CALIBRATION"])
+    .withMessage("Request type must be either MAINTENANCE or CALIBRATION"),
];
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export const createRequestValidation = [
  body("medicalEquipment")
    .notEmpty()
    .withMessage("Medical equipment ID is required"),

  body("complaint")
    .optional()
    .isString()
    .withMessage("Complaint must be a string"),

  body("submissionDate")
    .notEmpty()
    .withMessage("Submission date is required")
    .isISO8601()
    .withMessage("Submission date must be a valid date"),

  body("userId")
    .notEmpty()
    .withMessage("User ID is required"),

  body("createdBy")
    .notEmpty()
    .withMessage("Created by is required"),

  body("requestType")
    .notEmpty()
    .withMessage("Request type is required")
    .isIn(["MAINTENANCE", "CALIBRATION"])
    .withMessage("Request type must be either MAINTENANCE or CALIBRATION"),
];
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-28T13:50:31Z
author_association: NONE
diff_hunk: @@ -0,0 +1,30 @@
+import { v4 as uuidv4 } from "uuid";
+import { IRequestService } from "./interface/request.service.interface";
+import { CreateRequestDTO, RequestResponseDTO } from "../dto/request.dto";
+import RequestRepository from "../repository/request.repository";
+
+class RequestService implements IRequestService {
+  private readonly requestRepository: RequestRepository;
+
+  constructor() {
+    this.requestRepository = new RequestRepository();
+  }
+
+  public async createRequest(
+    requestData: CreateRequestDTO,
+  ): Promise<RequestResponseDTO> {
+    try {
+      const result = await this.requestRepository.createRequest({
+        id: uuidv4(),
+        ...requestData,
+        status: "Pending",
+      });
+
+      return result;
+    } catch (error) {
+      throw error;
+    }
path: src/services/request.service.ts
user: login: coderabbitai[bot]
body: _🛠️ Refactor suggestion_

**Remove unnecessary try-catch block**

The try-catch block that simply rethrows the error is redundant and adds unnecessary complexity.


```diff
  public async createRequest(
    requestData: CreateRequestDTO,
  ): Promise<RequestResponseDTO> {
-   try {
      const result = await this.requestRepository.createRequest({
        id: uuidv4(),
        ...requestData,
        status: "Pending",
      });

      return result;
-   } catch (error) {
-     throw error;
-   }
  }
```


<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
  public async createRequest(
    requestData: CreateRequestDTO,
  ): Promise<RequestResponseDTO> {
      const result = await this.requestRepository.createRequest({
        id: uuidv4(),
        ...requestData,
        status: "Pending",
      });

      return result;
  }
`````

</details>

<!-- suggestion_end -->

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 Biome (1.9.4)</summary>

[error] 25-25: The catch clause that only rethrows the original error is useless.

An unnecessary catch clause can be confusing.
Unsafe fix: Remove the try/catch clause.


(lint/complexity/noUselessCatch)

</details>

</details>

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-28T13:50:31Z
author_association: NONE
diff_hunk: @@ -0,0 +1,22 @@
+import { Request } from "@prisma/client";
+
+export interface RequesDTO extends Request {}
+
+export interface CreateRequestDTO {
+  userId: string;
+  medicalEquipment: string;
+  complaint?: string;
+  submissionDate: Date;
+  createdBy: string;
+  requestType: "MAINTENANCE" | "CALIBRATION";
+}
+
+export interface RequestResponseDTO {
+  id: string;
+  userID: string;
+  medicalEquipment: string;
+  complaint?: string;
+  submissionDate: Date;
+  status: string;
+  requestType: string;
+}
path: src/dto/request.dto.ts
user: login: coderabbitai[bot]
body: _⚠️ Potential issue_

**Fix inconsistency in field naming between DTOs.**

There's an inconsistency in field naming between DTOs:
- `CreateRequestDTO` uses `userId` (lowercase 'id')
- `RequestResponseDTO` uses `userID` (uppercase 'ID')

Additionally, `requestType` in `RequestResponseDTO` is just a string, which is less type-safe than the union type used in `CreateRequestDTO`.

```diff
export interface RequestResponseDTO {
  id: string;
-  userID: string;
+  userId: string;
  medicalEquipment: string;
  complaint?: string;
  submissionDate: Date;
  status: string;
-  requestType: string;
+  requestType: "MAINTENANCE" | "CALIBRATION";
}
```

This inconsistency could lead to mapping issues between the DTOs and database models.



<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

`````suggestion
export interface RequestResponseDTO {
  id: string;
  userId: string;
  medicalEquipment: string;
  complaint?: string;
  submissionDate: Date;
  status: string;
  requestType: "MAINTENANCE" | "CALIBRATION";
}
`````

</details>

<!-- suggestion_end -->

<!-- This is an auto-generated comment by CodeRabbit -->
created_at: 2025-04-28T13:50:32Z
author_association: NONE

PR comments:
user: login: coderabbitai[bot]
created_at: 2025-04-28T13:41:31Z
body: <!-- This is an auto-generated comment: summarize by coderabbit.ai -->
<!-- This is an auto-generated comment: skip review by coderabbit.ai -->

> [!IMPORTANT]
> ## Review skipped
> 
> Auto reviews are disabled on this repository.
> 
> Please check the settings in the CodeRabbit UI or the `.coderabbit.yaml` file in this repository. To trigger a single review, invoke the `@coderabbitai review` command.
> 
> You can disable this status message by setting the `reviews.review_status` to `false` in the CodeRabbit configuration file.

<!-- end of auto-generated comment: skip review by coderabbit.ai -->
<!-- walkthrough_start -->

## Walkthrough

This update introduces a complete feature for handling maintenance and calibration requests in an Express-based application. It adds new controller, service, repository, and route modules for request creation, along with associated DTOs, validation middleware, and service interfaces. The request creation flow is fully unit tested at the controller, service, repository, and route levels. The main application is updated to register the new request routes. All components are implemented in TypeScript and are integrated using dependency injection and standard Express middleware patterns.

## Changes

| File(s)                                                                                  | Change Summary                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
|------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `src/controllers/request.controller.ts`                                                  | Added `RequestController` class with methods for creating maintenance and calibration requests, delegating to the service layer, and handling errors via middleware.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `src/services/request.service.ts`, `src/services/interface/request.service.interface.ts` | Introduced `RequestService` class implementing `IRequestService` interface, encapsulating business logic for request creation, including UUID generation and status assignment. The interface defines the contract for request creation.                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `src/repository/request.repository.ts`                                                   | Added `RequestRepository` class to handle database operations for creating requests using Prisma ORM, including timestamp management.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| `src/dto/request.dto.ts`                                                                 | Introduced DTO interfaces: `RequesDTO`, `CreateRequestDTO`, and `RequestResponseDTO` to define the structure of request data for creation and response.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `src/routes/request.route.ts`                                                            | Added Express router for `/maintenance` and `/calibration` POST endpoints, applying authentication and validation middleware, and delegating to controller methods.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| `src/validations/request.validation.ts`                                                  | Added `createRequestValidation` middleware array using `express-validator` to enforce required fields and formats for request creation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `src/index.ts`                                                                           | Registered the new request routes under `/request` in the main Express application.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `__tests__/unit/controllers/request/add-request.controller.unit.test.ts`                 | Added unit tests for `RequestController` methods, verifying service calls, response formatting, and error propagation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| `__tests__/unit/services/request/add-request.service.unit.test.ts`                       | Added unit tests for `RequestService`, covering successful request creation for both types and error handling when repository operations fail.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |
| `__tests__/unit/repository/request/add-request.repository.unit.test.ts`                  | Added unit tests for `RequestRepository`'s `createRequest` method, validating correct Prisma calls, timestamp usage, and error propagation.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| `__tests__/unit/routes/request/request.route.unit.test.ts`                               | Added unit tests for route setup, ensuring correct middleware and handler registration for maintenance and calibration endpoints.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |

## Sequence Diagram(s)

```mermaid
sequenceDiagram
    participant Client
    participant Router
    participant Middleware
    participant RequestController
    participant RequestService
    participant RequestRepository
    participant Database

    Client->>Router: POST /request/maintenance or /request/calibration
    Router->>Middleware: verifyToken, createRequestValidation, validateRequest
    Middleware->>RequestController: createMaintenanceRequest/createCalibrationRequest
    RequestController->>RequestService: createRequest(requestData)
    RequestService->>RequestRepository: createRequest(augmentedRequestData)
    RequestRepository->>Database: INSERT request
    Database-->>RequestRepository: Created request
    RequestRepository-->>RequestService: Created request
    RequestService-->>RequestController: Created request
    RequestController-->>Middleware: res.status(201).json({ ... })
    Middleware-->>Client: HTTP 201 + JSON response
```

## Suggested reviewers

- daffagrahito

<!-- walkthrough_end -->
<!-- internal state start -->


<!-- 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 -->

<!-- internal state end -->
<!-- tips_start -->

---

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

<details>
<summary>❤️ Share</summary>

- [X](https://twitter.com/intent/tweet?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A&url=https%3A//coderabbit.ai)
- [Mastodon](https://mastodon.social/share?text=I%20just%20used%20%40coderabbitai%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20the%20proprietary%20code.%20Check%20it%20out%3A%20https%3A%2F%2Fcoderabbit.ai)
- [Reddit](https://www.reddit.com/submit?title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&text=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code.%20Check%20it%20out%3A%20https%3A//coderabbit.ai)
- [LinkedIn](https://www.linkedin.com/sharing/share-offsite/?url=https%3A%2F%2Fcoderabbit.ai&mini=true&title=Great%20tool%20for%20code%20review%20-%20CodeRabbit&summary=I%20just%20used%20CodeRabbit%20for%20my%20code%20review%2C%20and%20it%27s%20fantastic%21%20It%27s%20free%20for%20OSS%20and%20offers%20a%20free%20trial%20for%20proprietary%20code)

</details>

<details>
<summary>🪧 Tips</summary>

### Chat

There are 3 ways to chat with [CodeRabbit](https://coderabbit.ai?utm_source=oss&utm_medium=github&utm_campaign=RSUMMI-PPL-C5/INVENTUM-BE&utm_content=103):

- Review comments: Directly reply to a review comment made by CodeRabbit. Example:
  - `I pushed a fix in commit <commit_id>, please review it.`
  - `Generate unit testing code for this file.`
  - `Open a follow-up GitHub issue for this discussion.`
- Files and specific lines of code (under the "Files changed" tab): Tag `@coderabbitai` in a new review comment at the desired location with your query. Examples:
  - `@coderabbitai generate unit testing code for this file.`
  -	`@coderabbitai modularize this function.`
- PR comments: Tag `@coderabbitai` in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
  - `@coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.`
  - `@coderabbitai read src/utils.ts and generate unit testing code.`
  - `@coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.`
  - `@coderabbitai help me debug CodeRabbit configuration file.`

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

### CodeRabbit Commands (Invoked using PR comments)

- `@coderabbitai pause` to pause the reviews on a PR.
- `@coderabbitai resume` to resume the paused reviews.
- `@coderabbitai review` to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
- `@coderabbitai full review` to do a full review from scratch and review all the files again.
- `@coderabbitai summary` to regenerate the summary of the PR.
- `@coderabbitai generate docstrings` to [generate docstrings](https://docs.coderabbit.ai/finishing-touches/docstrings) for this PR.
- `@coderabbitai generate sequence diagram` to generate a sequence diagram of the changes in this PR.
- `@coderabbitai resolve` resolve all the CodeRabbit review comments.
- `@coderabbitai configuration` to show the current CodeRabbit configuration for the repository.
- `@coderabbitai help` to get help.

### Other keywords and placeholders

- Add `@coderabbitai ignore` anywhere in the PR description to prevent this PR from being reviewed.
- Add `@coderabbitai summary` to generate the high-level summary at a specific location in the PR description.
- Add `@coderabbitai` anywhere in the PR title to generate the title automatically.

### CodeRabbit Configuration File (`.coderabbit.yaml`)

- You can programmatically configure CodeRabbit by adding a `.coderabbit.yaml` file to the root of your repository.
- Please see the [configuration documentation](https://docs.coderabbit.ai/guides/configure-coderabbit) for more information.
- If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: `# yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json`

### Documentation and Community

- Visit our [Documentation](https://docs.coderabbit.ai) for detailed information on how to use CodeRabbit.
- Join our [Discord Community](http://discord.gg/coderabbit) to get help, request features, and share feedback.
- Follow us on [X/Twitter](https://twitter.com/coderabbitai) for updates and announcements.

</details>

<!-- tips_end -->
author_association: NONE
user: login: farrelsheva
created_at: 2025-04-28T13:47:06Z
body: @coderabbitai review
author_association: CONTRIBUTOR
user: login: coderabbitai[bot]
created_at: 2025-04-28T13:47:15Z
body: <!-- This is an auto-generated reply by CodeRabbit -->
<details>
<summary>✅ Actions performed</summary>

Review triggered.

> Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

</details>
author_association: NONE
user: login: daffagrahito
created_at: 2025-04-28T14:37:24Z
body: Menurut gua udah ok sih, mungkin ada hal yang bisa diperhatiin kayak itu validasi requestType. Itu menurut gua juga gapapa ditambahin begitu karena bisa jadi security, input validation dan sanitization bisa diperhatiin lagi kalau mau ngecek request yang didapet dari user. Sebenernya kalau dilihat dari coderabbit juga kelihatan jelas juga ada dua solusinya disitu. Sisanya ok sih good 👍
author_association: CONTRIBUTOR
user: login: azmyar
created_at: 2025-04-28T18:18:43Z
body: Fix konsistensi nama field aja, ganti userID jadi userId biar seragam. Terus, requestType mending pake tipe union kayak di CreateRequestDTO buat lebih type-safe. Mantep lel!
author_association: CONTRIBUTOR