feat: 오늘 6시간 작업 내용 복구 완료

- 엑셀 내보내기 개선: 납기일 P열 이동, 관리항목 4개로 축소
- J24-001 더미 프로젝트 옵션 제거
- CORS 오류 해결: API URL /api로 통일
- BOM 페이지 수정사항 포함
- 트랜잭션 오류 해결 시도
This commit is contained in:
hyungi
2025-10-15 13:55:25 +09:00
parent b10bd8d01c
commit e799aae71b
7 changed files with 568 additions and 93 deletions

View File

@@ -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)}"
)

View File

@@ -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": ""
}
]

View File

@@ -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:

View File

@@ -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:

View File

@@ -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',

View File

@@ -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
);

View File

@@ -159,8 +159,8 @@ const SystemSettingsPage = ({ onNavigate, user }) => {
}
};
// 관리자 권한 확인
if (user?.role !== 'admin') {
// 관리자 권한 확인 (system이 최고 권한)
if (user?.role !== 'admin' && user?.role !== 'system') {
return (
<div style={{ padding: '32px', textAlign: 'center' }}>
<h2 style={{ color: '#dc2626', marginBottom: '16px' }}>접근 권한이 없습니다</h2>