diff --git a/backend/app/routers/purchase_request.py b/backend/app/routers/purchase_request.py index 39d0d92..51299a8 100644 --- a/backend/app/routers/purchase_request.py +++ b/backend/app/routers/purchase_request.py @@ -34,7 +34,7 @@ class PurchaseRequestCreate(BaseModel): @router.post("/create") async def create_purchase_request( request_data: PurchaseRequestCreate, - # current_user: dict = Depends(get_current_user), + current_user: dict = Depends(get_current_user), db: Session = Depends(get_db) ): """ @@ -81,7 +81,7 @@ async def create_purchase_request( material_count, excel_file_path, requested_by ) VALUES ( :request_no, :file_id, :job_no, :category, - :material_count, :excel_path, :requested_by + :material_count, :excel_file_path, :requested_by ) RETURNING request_id """) @@ -91,8 +91,8 @@ async def create_purchase_request( "job_no": request_data.job_no, "category": request_data.category, "material_count": len(request_data.material_ids), - "excel_path": excel_filename, # 엑셀 파일명 저장 (JSON 대신) - "requested_by": 1 # current_user.get("user_id") + "excel_file_path": excel_filename, # 엑셀 파일명 저장 (JSON 대신) + "requested_by": current_user.get("user_id") }) request_id = result.fetchone().request_id @@ -163,7 +163,7 @@ async def create_purchase_request( db.rollback() logger.error(f"Failed to create purchase request: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"구매신청 생성 실패: {str(e)}" ) @@ -194,7 +194,7 @@ async def get_purchase_requests( u.name as requested_by, f.original_filename, j.job_name, - COUNT(pri.item_id) as item_count + COUNT(pri.id) as item_count FROM purchase_requests pr LEFT JOIN users u ON pr.requested_by = u.user_id LEFT JOIN files f ON pr.file_id = f.id @@ -244,7 +244,7 @@ async def get_purchase_requests( except Exception as e: logger.error(f"Failed to get purchase requests: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"구매신청 목록 조회 실패: {str(e)}" ) @@ -400,7 +400,7 @@ async def get_request_materials( except Exception as e: logger.error(f"Failed to get request materials: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"구매신청 자재 조회 실패: {str(e)}" ) @@ -451,7 +451,7 @@ async def download_request_excel( except Exception as e: logger.error(f"Failed to download request excel: {str(e)}") raise HTTPException( - status_code=status.HTTP_500_INTERNAL_SERVER_ERROR, + status_code=500, detail=f"엑셀 다운로드 실패: {str(e)}" ) diff --git a/backend/exports/PR-20251014-001.json b/backend/exports/PR-20251014-001.json index 7889920..3b7cb69 100644 --- a/backend/exports/PR-20251014-001.json +++ b/backend/exports/PR-20251014-001.json @@ -1,100 +1,575 @@ { "request_no": "PR-20251014-001", "job_no": "테스트용", - "created_at": "2025-10-14T06:47:25.065166", + "created_at": "2025-10-14T22:16:10.998006", "materials": [ { - "material_id": 2013, - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "1\"", - "material_grade": "SS", - "quantity": 6, - "unit": "EA", - "user_requirement": "" - }, - { - "material_id": 2019, - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", + "material_id": 60768, + "description": "PIPE, SMLS, SCH 40S, ASTM A312 TP304", + "category": "PIPE", "size": "1/2\"", - "material_grade": "SS", - "quantity": 5, + "material_grade": "ASTM A312 TP304", + "quantity": 11, "unit": "EA", "user_requirement": "" }, { - "material_id": 2024, - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "SS", - "quantity": 2, - "unit": "EA", - "user_requirement": "" - }, - { - "material_id": 2027, - "description": "STRAINER, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "-", - "quantity": 1, + "material_id": 60776, + "description": "PIPE, SMLS, SCH 80, ASTM A106 B", + "category": "PIPE", + "size": "3/4\"", + "material_grade": "ASTM A106 B", + "quantity": 92, "unit": "EA", "user_requirement": "" } ], "grouped_materials": [ { - "group_key": "SIGHT GLASS, FLG, 150LB|1\"|undefined|SS", + "group_key": "PIPE, SMLS, SCH 40S, ASTM A312 TP304|1/2\"|undefined|ASTM A312 TP304", "material_ids": [ - 2013 + 60768 ], - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "1\"", - "material_grade": "SS", - "quantity": 6, - "unit": "EA", - "user_requirement": "" - }, - { - "group_key": "SIGHT GLASS, FLG, 150LB|1/2\"|undefined|SS", - "material_ids": [ - 2019 - ], - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", + "description": "PIPE, SMLS, SCH 40S, ASTM A312 TP304", + "category": "PIPE", "size": "1/2\"", - "material_grade": "SS", - "quantity": 5, - "unit": "EA", + "material_grade": "ASTM A312 TP304", + "quantity": 11, + "unit": "m", + "total_length": 1395.1, + "pipe_lengths": [ + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 155, + "quantity": 1, + "totalLength": 155 + }, + { + "length": 155, + "quantity": 1, + "totalLength": 155 + }, + { + "length": 200, + "quantity": 1, + "totalLength": 200 + }, + { + "length": 245.1, + "quantity": 1, + "totalLength": 245.1 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + } + ], "user_requirement": "" }, { - "group_key": "SIGHT GLASS, FLG, 150LB|2\"|undefined|SS", + "group_key": "PIPE, SMLS, SCH 80, ASTM A106 B|3/4\"|undefined|ASTM A106 B", "material_ids": [ - 2024 + 60776 ], - "description": "SIGHT GLASS, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "SS", - "quantity": 2, - "unit": "EA", - "user_requirement": "" - }, - { - "group_key": "STRAINER, FLG, 150LB|2\"|undefined|-", - "material_ids": [ - 2027 + "description": "PIPE, SMLS, SCH 80, ASTM A106 B", + "category": "PIPE", + "size": "3/4\"", + "material_grade": "ASTM A106 B", + "quantity": 92, + "unit": "m", + "total_length": 7920.2, + "pipe_lengths": [ + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 60, + "quantity": 1, + "totalLength": 60 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 43.3, + "quantity": 1, + "totalLength": 43.3 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 50, + "quantity": 1, + "totalLength": 50 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 70, + "quantity": 1, + "totalLength": 70 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 76.2, + "quantity": 1, + "totalLength": 76.2 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 77.6, + "quantity": 1, + "totalLength": 77.6 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 80, + "quantity": 1, + "totalLength": 80 + }, + { + "length": 88.6, + "quantity": 1, + "totalLength": 88.6 + }, + { + "length": 88.6, + "quantity": 1, + "totalLength": 88.6 + }, + { + "length": 98.4, + "quantity": 1, + "totalLength": 98.4 + }, + { + "length": 98.4, + "quantity": 1, + "totalLength": 98.4 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 100, + "quantity": 1, + "totalLength": 100 + }, + { + "length": 120, + "quantity": 1, + "totalLength": 120 + }, + { + "length": 120, + "quantity": 1, + "totalLength": 120 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 150, + "quantity": 1, + "totalLength": 150 + }, + { + "length": 223.6, + "quantity": 1, + "totalLength": 223.6 + } ], - "description": "STRAINER, FLG, 150LB", - "category": "FLANGE", - "size": "2\"", - "material_grade": "-", - "quantity": 1, - "unit": "EA", "user_requirement": "" } ] diff --git a/docker-compose.proxy.yml b/docker-compose.proxy.yml index b46bbf5..921b60f 100644 --- a/docker-compose.proxy.yml +++ b/docker-compose.proxy.yml @@ -4,7 +4,7 @@ services: container_name: tk-mp-nginx-proxy restart: unless-stopped ports: - - "80:80" + - "8808:80" volumes: - ./nginx-proxy.conf:/etc/nginx/conf.d/default.conf networks: diff --git a/docker-compose.yml b/docker-compose.yml index 4af1f7b..db032d4 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -78,13 +78,13 @@ services: context: ./frontend dockerfile: Dockerfile args: - - VITE_API_URL=${VITE_API_URL:-http://localhost:18000} + - VITE_API_URL=${VITE_API_URL:-/api} container_name: tk-mp-frontend restart: unless-stopped ports: - - "${FRONTEND_PORT:-13000}:5173" + - "${FRONTEND_PORT:-13000}:3000" environment: - - VITE_API_URL=${VITE_API_URL:-http://localhost:18000} + - VITE_API_URL=${VITE_API_URL:-/api} depends_on: - backend networks: diff --git a/frontend/src/App.jsx b/frontend/src/App.jsx index d6d98ba..e193af9 100644 --- a/frontend/src/App.jsx +++ b/frontend/src/App.jsx @@ -229,9 +229,11 @@ function App() { console.log('getAdminFeatures - Current user:', user); console.log('getAdminFeatures - User role:', user?.role); console.log('getAdminFeatures - Pending count:', pendingSignupCount); + console.log('getAdminFeatures - Role check result:', user?.role === 'system' || user?.role === 'admin'); - // 시스템 관리자 기능 (admin role이 시스템 관리자) - if (user?.role === 'admin') { + // 시스템 관리자 기능 (system role이 최고 권한) + if (user?.role === 'system' || user?.role === 'admin') { + console.log('✅ 시스템 관리자 기능 추가 중...'); features.push( { id: 'user-management', diff --git a/frontend/src/pages/NewMaterialsPage.jsx b/frontend/src/pages/NewMaterialsPage.jsx index 2b027a6..980dbd9 100644 --- a/frontend/src/pages/NewMaterialsPage.jsx +++ b/frontend/src/pages/NewMaterialsPage.jsx @@ -1386,11 +1386,9 @@ const NewMaterialsPage = ({ const timestamp = new Date().toISOString().split('T')[0]; const fileName = `${jobNo}_${selectedCategory}_${timestamp}.xlsx`; - // BOM 페이지에서 사용하는 엑셀 내보내기 함수 사용 - await exportCategoryToExcel( - selectedCategory, + // 기존 엑셀 내보내기 함수 사용 + await exportMaterialsToExcel( dataWithRequirements, - jobNo, fileName, userRequirements ); diff --git a/frontend/src/pages/SystemSettingsPage.jsx b/frontend/src/pages/SystemSettingsPage.jsx index b437edd..c40a628 100644 --- a/frontend/src/pages/SystemSettingsPage.jsx +++ b/frontend/src/pages/SystemSettingsPage.jsx @@ -159,8 +159,8 @@ const SystemSettingsPage = ({ onNavigate, user }) => { } }; - // 관리자 권한 확인 - if (user?.role !== 'admin') { + // 관리자 권한 확인 (system이 최고 권한) + if (user?.role !== 'admin' && user?.role !== 'system') { return (

접근 권한이 없습니다