From 5f778d9a2bca152f68b38a3260c12c0cf0b8f193 Mon Sep 17 00:00:00 2001
From: chpark <chpark@gdnsi.com>
Date: Mon, 23 Dec 2024 19:07:20 +0900
Subject: [PATCH] =?UTF-8?q?=EA=B3=A0=EA=B0=9D=EC=82=AC=20=EB=93=B1?=
 =?UTF-8?q?=EB=A1=9D=20=EC=99=84=EB=A3=8C?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../app/common/oemmng.controller.js           | 114 ++++++++++++++++++
 plm-api/src/models/Company.js                 |   1 +
 plm-api/src/models/OemMng.js                  |  17 ++-
 plm-api/src/routes/app.js                     |   2 +
 plm-api/src/services/oemmng.service.js        | 109 ++++++-----------
 .../common/oemmng/components/OemMngForm.tsx   |   4 +-
 .../src/app/(admin)/common/oemmng/page.tsx    |  65 +++++-----
 plm-app/src/types/common/oemmng/oemmng.ts     |   2 +
 8 files changed, 207 insertions(+), 107 deletions(-)
 create mode 100644 plm-api/src/controllers/app/common/oemmng.controller.js

diff --git a/plm-api/src/controllers/app/common/oemmng.controller.js b/plm-api/src/controllers/app/common/oemmng.controller.js
new file mode 100644
index 0000000..a04ccc2
--- /dev/null
+++ b/plm-api/src/controllers/app/common/oemmng.controller.js
@@ -0,0 +1,114 @@
+// src/controllers/admin/users/users.controller.js
+const express = require("express");
+const router = express.Router();
+const oemMngService = require("../../../services/oemmng.service");
+const authMiddleware = require("../../../middleware/auth.middleware");
+const roleCheck = require("../../../middleware/roleCheck.middleware");
+const { body, param } = require("express-validator");
+const validate = require("../../../middleware/validator.middleware");
+
+router.use(authMiddleware);
+router.use(roleCheck(["super_admin", "company_admin"]));
+
+// 고객사 목록 조회
+router.get("/oemmngList", async (req, res, next) => {
+  try {
+    const page = parseInt(req.query.page) || 1;
+    const limit = parseInt(req.query.limit) || 10;
+
+    const result = await oemMngService.findAll(req.user, page, limit);
+    res.json(result);
+  } catch (error) {
+    next(error);
+  }
+});
+
+// Create OemMng
+router.post(
+  "/oemmngCreate",
+  [
+    body("oem_code").notEmpty().withMessage("OEM 코드가 필요합니다"),
+    body("oem_name").notEmpty().withMessage("OEM 이름이 필요합니다"),
+    body("companyId").isUUID().withMessage("유효한 회사 ID가 필요합니다"),
+    validate,
+  ],
+  async (req, res, next) => {
+    try {
+      const oemMng = await oemMngService.createOemMng(req.body, req.user);
+      res.status(201).json(oemMng);
+    } catch (error) {
+      next(error);
+    }
+  }
+);
+
+// Update OemMng
+router.put(
+  "/oemmngUpdate/:id",
+  [
+    param("id").isUUID().withMessage("유효한 ID가 필요합니다"),
+    body("oem_code").optional().notEmpty().withMessage("OEM 코드가 필요합니다"),
+    body("oem_name").optional().notEmpty().withMessage("OEM 이름이 필요합니다"),
+    body("companyId").optional().isUUID().withMessage("유효한 회사 ID가 필요합니다"),
+    validate,
+  ],
+  async (req, res, next) => {
+    try {
+      const oemMng = await oemMngService.findById(req.params.id);
+
+      if (!oemMng) {
+        return res.status(404).json({ message: "고객사를 찾을 수 없습니다" });
+      }
+
+      // company_admin은 자신의 회사 고객사만 수정 가능
+      if (
+        req.user.role === "company_admin" &&
+        oemMng.companyId !== req.user.companyId
+      ) {
+        return res.status(403).json({
+          message: "다른 회사의 고객사를 수정할 수 없습니다",
+        });
+      }
+
+      const updatedOemMng = await oemMngService.updateOemMng(req.params.id, req.body, req.user);
+      res.json(updatedOemMng);
+    } catch (error) {
+      next(error);
+    }
+  }
+);
+
+// Delete OemMng
+router.delete(
+  "/oemmngDelete/:id",
+  [
+    param("id").isUUID().withMessage("유효한 ID가 필요합니다"),
+    validate,
+  ],
+  async (req, res, next) => {
+    try {
+      const oemMng = await oemMngService.findById(req.params.id);
+
+      if (!oemMng) {
+        return res.status(404).json({ message: "고객사를 찾을 수 없습니다" });
+      }
+
+      // company_admin은 자신의 회사 고객사만 삭제 가능
+      if (
+        req.user.role === "company_admin" &&
+        oemMng.companyId !== req.user.companyId
+      ) {
+        return res.status(403).json({
+          message: "다른 회사의 고객사를 삭제할 수 없습니다",
+        });
+      }
+
+      await oemMngService.deleteOemMng(req.params.id, req.user);
+      res.status(204).end();
+    } catch (error) {
+      next(error);
+    }
+  }
+);
+
+module.exports = router;
diff --git a/plm-api/src/models/Company.js b/plm-api/src/models/Company.js
index 0918f6e..69623de 100644
--- a/plm-api/src/models/Company.js
+++ b/plm-api/src/models/Company.js
@@ -67,6 +67,7 @@ class Company extends Model {
     this.hasMany(models.Equipment, { foreignKey: "companyId" });
     this.hasMany(models.MaintenanceLog, { foreignKey: "companyId" });
     this.hasMany(models.ApiKey, { foreignKey: "companyId" });
+    this.hasMany(models.OemMng, { foreignKey: "companyId" });
   }
 }
 
diff --git a/plm-api/src/models/OemMng.js b/plm-api/src/models/OemMng.js
index 572c18a..4689b38 100644
--- a/plm-api/src/models/OemMng.js
+++ b/plm-api/src/models/OemMng.js
@@ -27,14 +27,19 @@ class OemMng extends Model {
           type: DataTypes.DATE,
           allowNull: true,
         },
-        status: {
-          type: DataTypes.STRING(32),
-          allowNull: true,
+        isActive: {
+          type: DataTypes.BOOLEAN,
+          defaultValue: true,
         },
         oem_no: {
           type: DataTypes.STRING(32),
           allowNull: true,
         },
+        // 새로 추가할 필드들
+        companyId: {
+          type: DataTypes.UUID,
+          comment: "회사 ID",
+        },
       },
       {
         sequelize,
@@ -50,6 +55,12 @@ class OemMng extends Model {
     );
     return this;
   }
+
+  static associate(models) {
+    // OemMng이 Company에 속함
+    this.belongsTo(models.Company, { foreignKey: "companyId" });
+  }
+
 }
 
 module.exports = OemMng;
\ No newline at end of file
diff --git a/plm-api/src/routes/app.js b/plm-api/src/routes/app.js
index 4e572c6..afb3f5b 100644
--- a/plm-api/src/routes/app.js
+++ b/plm-api/src/routes/app.js
@@ -17,6 +17,7 @@ const healthController = require("../controllers/app/health/health.controller");
 const companiesController = require("../controllers/admin/companies/companies.controller");
 const deviceController = require("../controllers/app/device/device.controller");
 const commonController = require("../controllers/app/common/common.controller");
+const oemMngController = require("../controllers/app/common/oemmng.controller");
 
 router.use("/health", healthController);
 router.use("/auth", authController);
@@ -33,5 +34,6 @@ router.use("/department", departmentController);
 router.use("/companies", companiesController);
 router.use("/devices", deviceController);
 router.use("/common", commonController);
+router.use("/oemmng", oemMngController);
 
 module.exports = router;
diff --git a/plm-api/src/services/oemmng.service.js b/plm-api/src/services/oemmng.service.js
index e6238d5..b319ab1 100644
--- a/plm-api/src/services/oemmng.service.js
+++ b/plm-api/src/services/oemmng.service.js
@@ -1,53 +1,36 @@
-// src/services/oemmng.service.js
 const {
-  User,
+  OemMng,
   Company,
-  Branch,
-  Department,
-  UserRole,
   Role,
 } = require("../models");
-const { Op } = require("sequelize");
+//const { Op } = require("sequelize");
 const alertService = require("./alert.service");
 
 class OemMngService {
   async findAll(currentUser, page = 1, limit = 10) {
     try {
       // Initialize the where clause
-      let where = {
-        role: { [Op.ne]: "super_admin" }, // Exclude super_admin users
-      };
+      let where = {};
 
       // company_admin은 자신의 회사 유저만 조회 가능
       if (currentUser.role === "company_admin") {
         where.companyId = currentUser.companyId;
       }
+      // isActive 필터 추가
+      //where.isActive = { [Op.eq]: true };
 
       const offset = (page - 1) * limit;
 
       // 전체 개수 조회
-      const count = await User.count({ where });
+      const count = await OemMng.count({ where });
 
-      const users = await User.findAll({
+      const oemMngs = await OemMng.findAll({
         where,
         include: [
           {
             model: Company,
             attributes: ["id", "name"],
           },
-          {
-            model: Branch,
-            attributes: ["id", "name"],
-          },
-          {
-            model: Department,
-            attributes: ["id", "name"],
-          },
-          {
-            model: Role,
-            through: { attributes: [] },
-            attributes: ["id", "name", "description"],
-          },
         ],
         order: [["createdAt", "DESC"]],
         offset,
@@ -56,17 +39,17 @@ class OemMngService {
       });
 
       // 인덱스 추가
-      const usersWithIndex = users.map((user, index) => {
-        const userJson = user.toJSON();
-        userJson.index = offset + index + 1;
-        return userJson;
+      const oemMngsWithIndex = oemMngs.map((oem, index) => {
+        const oemJson = oem.toJSON();
+        oemJson.index = offset + index + 1;
+        return oemJson;
       });
 
       return {
         total: count,
         totalPages: Math.ceil(count / limit),
         currentPage: page,
-        users: usersWithIndex,
+        oemMngs: oemMngsWithIndex,
       };
     } catch (error) {
       console.error("Error in findAll:", error);
@@ -75,34 +58,26 @@ class OemMngService {
   }
 
   async findById(id) {
-    return await User.findByPk(id, {
+    return await OemMng.findByPk(id, {
       include: [
         {
           model: Company,
           attributes: ["id", "name"],
         },
-        {
-          model: Branch,
-          attributes: ["id", "name"],
-        },
-        {
-          model: Department,
-          attributes: ["id", "name"],
-        },
       ],
     });
   }
 
-  async createUser(userData, currentUser) {
-    const { roleId, ...userFields } = userData;
+  async createOemMng(oemMngData, currentUser) {
+    const { roleId, ...oemMngFields } = oemMngData;
 
-    const user = await User.create(userFields);
+    const oemMng = await OemMng.create(oemMngFields);
 
     if (roleId) {
       const role = await Role.findOne({
         where: {
           id: roleId,
-          companyId: user.companyId,
+          companyId: oemMng.companyId,
         },
       });
 
@@ -110,26 +85,23 @@ class OemMngService {
         throw new Error("Role not found or does not belong to the company");
       }
 
-      await UserRole.create({
-        userId: user.id,
-        roleId: role.id,
-      });
+      await oemMng.addRole(role);
     }
 
     await alertService.createAlert({
       type: "info",
-      message: `유저 ${user.name}이(가) ${currentUser.name}에 의해 생성되었습니다.`,
-      companyId: user.companyId,
+      message: `고객사 ${oemMng.name}이(가) ${currentUser.name}에 의해 생성되었습니다.`,
+      companyId: oemMng.companyId,
     });
 
-    return user;
+    return oemMng;
   }
 
-  async updateUser(id, updateData, currentUser) {
-    const { roleId, ...userFields } = updateData;
+  async updateOemMng(id, updateData, currentUser) {
+    const { roleId, ...oemMngFields } = updateData;
 
-    const user = await User.findByPk(id);
-    if (!user) throw new Error("User not found");
+    const oemMng = await OemMng.findByPk(id);
+    if (!oemMng) throw new Error("OemMng not found");
 
     // company_admin은 특정 필드를 수정할 수 없음 (예: role을 super_admin으로 변경 불가)
     if (currentUser.role === "company_admin") {
@@ -139,13 +111,13 @@ class OemMngService {
       updateData.companyId = currentUser.companyId;
     }
 
-    const updatedUser = await user.update(userFields);
+    const updatedOemMng = await oemMng.update(oemMngFields);
 
     if (roleId) {
       const role = await Role.findOne({
         where: {
           id: roleId,
-          companyId: user.companyId,
+          companyId: oemMng.companyId,
         },
       });
 
@@ -153,33 +125,30 @@ class OemMngService {
         throw new Error("Role not found or does not belong to the company");
       }
 
-      await UserRole.upsert({
-        userId: user.id,
-        roleId: role.id,
-      });
+      await oemMng.addRole(role);
     }
 
     await alertService.createAlert({
       type: "info",
-      message: `유저 ${user.name}이(가) ${currentUser.name}에 의해 수정되었습니다.`,
-      companyId: user.companyId,
+      message: `고객사 ${oemMng.name}이(가) ${currentUser.name}에 의해 수정되었습니다.`,
+      companyId: oemMng.companyId,
     });
 
-    return updatedUser;
+    return updatedOemMng;
   }
 
-  async deleteUser(id, currentUser) {
-    const user = await User.findByPk(id);
-    if (!user) throw new Error("User not found");
+  async deleteOemMng(id, currentUser) {
+    const oemMng = await OemMng.findByPk(id);
+    if (!oemMng) throw new Error("OemMng not found");
 
-    const userName = user.name;
-    const companyId = user.companyId;
+    const oemMngName = oemMng.name;
+    const companyId = oemMng.companyId;
 
-    await user.destroy();
+    await oemMng.destroy();
 
     await alertService.createAlert({
       type: "info",
-      message: `유저 ${userName}이(가) ${currentUser.name}에 의해 삭제되었습니다.`,
+      message: `고객사 ${oemMngName}이(가) ${currentUser.name}에 의해 삭제되었습니다.`,
       companyId: companyId,
     });
 
@@ -187,4 +156,4 @@ class OemMngService {
   }
 }
 
-module.exports = new UserService();
+module.exports = new OemMngService();
\ No newline at end of file
diff --git a/plm-app/src/app/(admin)/common/oemmng/components/OemMngForm.tsx b/plm-app/src/app/(admin)/common/oemmng/components/OemMngForm.tsx
index 1bf3365..49274b2 100644
--- a/plm-app/src/app/(admin)/common/oemmng/components/OemMngForm.tsx
+++ b/plm-app/src/app/(admin)/common/oemmng/components/OemMngForm.tsx
@@ -42,7 +42,7 @@ type FormSchema = z.infer<typeof formSchema>;
 
 interface OemFormProps {
   initialData?: Partial<oemMng>;
-  onSubmit: (data: Partial<User>) => void;
+  onSubmit: (data: Partial<oemMng>) => void;
   onCancel: () => void;
 }
 
@@ -51,7 +51,7 @@ export const OemMngForm: React.FC<OemFormProps> = ({
   onSubmit,
   onCancel,
 }) => {
-  const { token, user } = useAuthStore();
+  //const { token, user } = useAuthStore();
   const { toast } = useToast();
 
   // Initialize the form with react-hook-form and zod resolver
diff --git a/plm-app/src/app/(admin)/common/oemmng/page.tsx b/plm-app/src/app/(admin)/common/oemmng/page.tsx
index 109f1ea..ce90677 100644
--- a/plm-app/src/app/(admin)/common/oemmng/page.tsx
+++ b/plm-app/src/app/(admin)/common/oemmng/page.tsx
@@ -23,20 +23,21 @@ import { OemMngForm } from "./components/OemMngForm";
 import { Switch } from "@/components/ui/switch";
 import { oemMng, PaginatedResponse } from "@/types/common/oemmng/oemmng";
 
-const AccountsPage = () => {
+const OemMngPage = () => {
   const { token, user } = useAuthStore();
   const [isOpen, setIsOpen] = React.useState(false);
-  const [editingUser, setEditingUser] = React.useState<User | null>(null);
+  const [editingUser, setEditingUser] = React.useState<oemMng | null>(null);
   const [page, setPage] = useState(1);
   const [pageSize, setPageSize] = useState(10);
   const { toast } = useToast();
   const queryClient = useQueryClient();
 
-  // Fetch users with pagination
+  // Fetch OEMs with pagination
   const { data, isLoading } = useQuery<PaginatedResponse>({
-    queryKey: ["users", page, pageSize],
+    queryKey: ["oemMngs", page, pageSize],
     queryFn: async () => {
-      const { data } = await api.get("/api/v1/admin/users", {
+      const { data } = await api.get("/api/v1/app/oemmng/oemmngList", {
+
         params: {
           page,
           limit: pageSize,
@@ -44,15 +45,15 @@ const AccountsPage = () => {
       });
       return {
         ...data,
-        users: data.users.map((user: User) => ({
-          ...user,
-          Roles: user.Roles || [],
+        oemMngs: data.oemMngs.map((oemMngs: oemMng) => ({
+          ...oemMngs,
         })),
       };
     },
     enabled: !!token,
   });
 
+
   const handlePageSizeChange = useCallback((newPageSize: number) => {
     setPageSize(newPageSize);
     setPage(1);
@@ -60,21 +61,21 @@ const AccountsPage = () => {
 
   // Create user mutation
   const createMutation = useMutation({
-    mutationFn: async (newUser: Partial<User>) => {
+    mutationFn: async (newOem: Partial<oemMng>) => {
       // Include companyId in the user data
-      const userWithCompanyId = {
-        ...newUser,
+      const oemWithCompanyId = {
+        ...newOem,
         companyId: user?.companyId,
       };
 
-      const { data } = await api.post<User>(
-        "/api/v1/admin/users",
-        userWithCompanyId
+      const { data } = await api.post<oemMng>(
+        "/api/v1/app/oemmng/oemmngCreate",
+        oemWithCompanyId
       );
       return data;
     },
     onSuccess: () => {
-      queryClient.invalidateQueries({ queryKey: ["users"] });
+      queryClient.invalidateQueries({ queryKey: ["oemMngs"] });
       setIsOpen(false);
       toast({
         title: "고객사 생성",
@@ -92,15 +93,16 @@ const AccountsPage = () => {
 
   // Update user mutation
   const updateMutation = useMutation({
-    mutationFn: async (userData: Partial<User>) => {
-      const { data } = await api.put<User>(
-        `/api/v1/admin/users/${userData.id}`,
-        userData
+    mutationFn: async (oemData: Partial<oemMng>) => {
+      const { data } = await api.put<oemMng>(
+        `/api/v1/app/oemmng/oemmngUpdate/${oemData.id}`,
+        
+        oemData
       );
       return data;
     },
     onSuccess: () => {
-      queryClient.invalidateQueries({ queryKey: ["users"] });
+      queryClient.invalidateQueries({ queryKey: ["oemMngs"] });
       setIsOpen(false);
       setEditingUser(null);
       toast({
@@ -120,10 +122,10 @@ const AccountsPage = () => {
   // Delete user mutation
   const deleteMutation = useMutation({
     mutationFn: async (id: string) => {
-      await api.delete(`/api/v1/admin/users/${id}`);
+      await api.delete(`/api/v1/app/oemmng/oemmngDelete/${id}`);
     },
     onSuccess: () => {
-      queryClient.invalidateQueries({ queryKey: ["users"] });
+      queryClient.invalidateQueries({ queryKey: ["oemMngs"] });
       toast({
         title: "고객사 삭제",
         description: "고객사가 삭제되었습니다.",
@@ -139,7 +141,7 @@ const AccountsPage = () => {
   });
 
   // Table columns
-  const columns: ColumnDef<User>[] = [
+  const columns: ColumnDef<oemMng>[] = [
     {
       id: "index",
       header: "No",
@@ -151,13 +153,12 @@ const AccountsPage = () => {
     //   header: "아이디",
     // },
     {
-      accessorKey: "name",
-      header: "업체명/고객사사",
+      accessorKey: "oem_code",
+      header: "업체명/고객사",
     },
     {
-      accessorKey: "Department.name",
-      header: "업체/고객사코드드",
-      cell: ({ row }) => row.original.Department?.name || "-",
+      accessorKey: "oem_name",
+      header: "OEM 이름",
     },
     {
       accessorKey: "isActive",
@@ -220,17 +221,17 @@ const AccountsPage = () => {
         </Button>
       </div>
 
-      {/* Users Table */}
+      {/* OEMs Table */}
       <Card>
         <CardHeader>
           <CardTitle>고객사 목록</CardTitle>
         </CardHeader>
         <CardContent>
-          {data?.users && data.users.length > 0 ? (
+          {data?.oemMngs && data.oemMngs.length > 0 ? (
             <>
               <DataTable
                 columns={columns}
-                data={data.users}
+                data={data.oemMngs}
                 pagination={{
                   pageIndex: page - 1,
                   pageSize,
@@ -289,4 +290,4 @@ const AccountsPage = () => {
   );
 };
 
-export default AccountsPage;
+export default OemMngPage;
diff --git a/plm-app/src/types/common/oemmng/oemmng.ts b/plm-app/src/types/common/oemmng/oemmng.ts
index 4eabd8b..4e18392 100644
--- a/plm-app/src/types/common/oemmng/oemmng.ts
+++ b/plm-app/src/types/common/oemmng/oemmng.ts
@@ -2,12 +2,14 @@
 
 export interface oemMng {
   id: string;
+  index: number;
   oem_code?: string | null;
   oem_name?: string | null;
   writer?: string | null;
   regdate?: Date | null;
   status?: string | null;
   oem_no?: string | null;
+  isActive: boolean;
 }
 
 export interface oemMngResponse {