Files
sam-react-prod/claudedocs/item-master/[REF] item-code-hardcoding.md
byeongcheolryu 751e65f59b fix: 품목관리 수정 기능 버그 수정 및 Sales 페이지 추가
## 품목관리 수정 버그 수정
- FG(제품) 수정 시 품목명 반영 안되는 문제 해결
  - productName → name 필드 매핑 추가
  - FG 품목코드 = 품목명 동기화 로직 추가
- Materials(SM, RM, CS) 수정페이지 진입 오류 해결
- UNIQUE 제약조건 위반 오류 해결

## Sales 페이지
- 거래처관리 (client-management-sales-admin) 페이지 구현
- 견적관리 (quote-management) 페이지 구현
- 관련 컴포넌트 및 훅 추가

## 기타
- 회원가입 페이지 차단 처리
- 디버깅용 콘솔 로그 추가 (PUT 요청/응답 확인용)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-04 20:52:42 +09:00

557 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 품목관리 하드코딩 내역 종합 문서
> **MVP용 프론트엔드 구현** - 추후 품목기준관리 설정 또는 백엔드 API로 이관 필요
## 개요
품목기준관리에서 동적으로 설정해야 하지만 아직 해당 기능이 없어 프론트엔드에 하드코딩된 기능 목록입니다.
---
## 하드코딩 항목 요약
| # | 항목 | 파일 위치 | 우선순위 | 상태 |
|---|------|----------|---------|------|
| 1 | 품목유형 등록 (FG/PT/SM/RM/CS) | `ItemTypeSelect.tsx` | 🔴 High | 하드코딩 |
| 2 | 품목코드/품목명 자동생성 | `itemCodeGenerator.ts`, `DynamicItemForm/index.tsx` | 🔴 High | 하드코딩 |
| 3 | 전개도/바라시 섹션 (조립/절곡) | `DynamicItemForm/index.tsx` | 🟡 Medium | 하드코딩 |
| 4 | BOM 섹션 내부 구조 | `DynamicBOMSection.tsx` | 🟡 Medium | 하드코딩 |
| 5 | 부품유형 판별 로직 | `DynamicItemForm/index.tsx` | 🟢 Low | 하드코딩 |
| 6 | FG(제품) 시방서/인정서 파일업로드 | `DynamicItemForm/index.tsx` | 🟡 Medium | 하드코딩 |
---
## 1. 품목유형 등록 (FG/PT/SM/RM/CS)
### 파일 위치
`src/components/items/ItemTypeSelect.tsx`
### 하드코딩 내용
```typescript
const ITEM_TYPE_LABELS_WITH_ENGLISH: Record<ItemType, string> = {
FG: '제품 (Finished Goods)',
PT: '부품 (Part)',
SM: '부자재 (Sub Material)',
RM: '원자재 (Raw Material)',
CS: '소모품 (Consumables)',
};
```
### 문제점
- 품목유형 추가/수정/삭제 불가
- 각 유형별 표시 순서 고정
- 영문명 커스터마이징 불가
### 마이그레이션 방안
```yaml
Phase 1: 품목기준관리 API 확장
- item_types 테이블 생성
- GET /api/v1/item-master/types 엔드포인트 추가
- 응답: { code: 'FG', name: '제품', englishName: 'Finished Goods', sortOrder: 1 }
Phase 2: 프론트엔드 연동
- ItemTypeSelect에서 API 호출
- 품목기준관리에 품목유형 관리 UI 추가
```
---
## 2. 품목코드/품목명 자동생성
### 파일 위치
- **부품(PT)**: `src/components/items/DynamicItemForm/utils/itemCodeGenerator.ts`
- **제품(FG)**: `src/components/items/DynamicItemForm/index.tsx` (Lines: 1430-1444)
### 2-0. 제품(FG) 품목코드 규칙
```typescript
// 제품(FG)의 품목코드는 품목명과 동일 (조합식 없음)
// DynamicItemForm/index.tsx에서 직접 처리
{/* FG(제품) 전용: 품목명 필드 다음에 품목코드 자동생성 */}
{isItemNameField && selectedItemType === 'FG' && (
<div className="mt-4">
<Label htmlFor="fg_item_code_auto">품목코드 (자동생성)</Label>
<Input
id="fg_item_code_auto"
value={(formData[itemNameKey] as string) || ''}
placeholder="품목명이 입력되면 자동으로 동일하게 생성됩니다"
disabled
className="bg-muted text-muted-foreground"
/>
<p className="text-xs text-muted-foreground mt-1">
* 제품(FG) 품목코드는 품목명과 동일하게 설정됩니다
</p>
</div>
)}
```
**제품(FG) 특징**:
- 품목코드 = 품목명 (단순 복사)
- 조합식이나 영문약어 매핑 없음
- `isItemNameField` 플래그로 품목명 필드 다음에 자동으로 표시
### 2-1. 영문약어 매핑 테이블
```typescript
export const ITEM_CODE_PREFIX_MAP: Record<string, string> = {
// 부품 - 조립품
'가이드레일': 'GR',
'케이스': 'CASE',
'브라켓': 'BRK',
// 부품 - 구매품
'모터': 'MOTOR',
'제어기': 'CTL',
'전동개폐기': 'OPENER',
'스위치': 'SW',
'센서': 'SENSOR',
'리모컨': 'REMOTE',
// 부품 - 절곡품
'레일': 'RAIL',
'커버': 'COVER',
'플레이트': 'PLATE',
// 제품
'스크린': 'SCREEN',
'셔터': 'SHUTTER',
'방화스크린': 'FIRE-SCR',
'롤스크린': 'ROLL-SCR',
// 원자재
'알루미늄': 'ALU',
'스틸': 'STEEL',
'철판': 'STEEL',
// 부자재/소모품
'볼트': 'BOLT',
'너트': 'NUT',
'와셔': 'WASHER',
'나사': 'SCREW',
};
```
### 2-2. 절곡품 코드 체계
```typescript
export const BENDING_CODE_SYSTEM = {
// 품목명코드 (category2)
품목명코드: {
'R': '가이드레일',
'S': '스크린',
'C': '케이스',
'B': '박스',
'T': '트림',
'L': '라스틱',
'G': '기타',
},
// 종류코드 (category3)
종류코드: {
'M': '마감',
'T': '티',
'C': '채널',
'D': '단면',
'S': '상부',
'U': '하부',
'F': '플랫',
'P': '피스',
'L': '리드',
'B': '브라켓',
'E': '엔드',
'I': '이음',
'A': '각재',
},
// 길이코드 매핑 (mm → 코드)
길이코드: {
1219: '12',
2438: '24',
3000: '30',
3500: '35',
4000: '40',
4150: '41',
4200: '42',
4300: '43',
},
};
```
### 2-3. 조립품 설치유형 매핑
```typescript
export const INSTALLATION_TYPE_MAP: Record<string, string> = {
'standard': '표준형',
'top': '상부형',
'bottom': '하부형',
'side': '측면형',
'custom': '맞춤형',
};
```
### 자동생성 함수 목록
| 함수명 | 용도 | 형식 예시 |
|--------|------|----------|
| `generateItemCode` | PT 품목코드 | `GR-001`, `MOTOR-002` |
| `generateBendingItemCode` | 절곡품 품목코드 | `RC24` (가이드레일 채널 2438mm) |
| `generateAssemblyItemName` | 조립품 품목명 | `가이드레일표준형50*60*24` |
| `generateBendingItemName` | 절곡품 품목명 | `가이드레일 채널 50×30` |
| `generatePurchasedItemName` | 구매품 품목명 | `모터 0.4KW` |
### 마이그레이션 방안
```yaml
Phase 1: 품목기준관리 설정 확장
- 영문약어 필드 추가 (품목명 필드 옵션에 매핑)
- 코드생성규칙 설정 UI 추가
Phase 2: 백엔드 이관
- 품목 저장 시 백엔드에서 코드 자동 생성
- 순번 관리를 DB 시퀀스로 변경 (동시성 처리)
```
---
## 3. 전개도/바라시 섹션 (조립/절곡)
### 파일 위치
`src/components/items/DynamicItemForm/index.tsx` (Lines: 1474-1560)
### 하드코딩 내용
#### 3-1. 조립품 전개도 섹션 (바라시)
```typescript
{/* 조립품 전개도 섹션 (PT - 조립 부품 전용) */}
{selectedItemType === 'PT' && isAssemblyPart && assemblyItemNameKey && (
<BendingDiagramSection
title="조립품 전개도"
description="조립품 전개도(바라시)를 그리거나 편집합니다."
...
/>
)}
```
#### 3-2. 절곡품 전개도 섹션
```typescript
{/* 절곡품 전개도 섹션 (PT - 절곡 부품 전용) */}
{selectedItemType === 'PT' && isBendingPart && bendingFields.material && (
<BendingDiagramSection
title="절곡품 전개도"
description="절곡품 전개도를 그리거나 편집합니다."
...
/>
)}
```
### 문제점
- 전개도 섹션 표시 조건이 코드에 고정
- 조립/절곡 외 다른 부품유형에 전개도 추가 불가
- 전개도 섹션 필드 구성 변경 불가
### 데이터 구조 (저장 시)
```typescript
// 절곡품
{
bending_diagram: string | null, // 전개도 이미지 Base64
bending_details: BendingDetail[], // 전개도 상세 (좌표, 길이 등)
width_sum: string | null, // 폭 합계
shape_and_length: string | null, // 모양 & 길이
}
// 조립품 (동일 필드 사용)
{
bending_diagram: string | null,
width_sum: string | null,
shape_and_length: string | null,
}
```
### 마이그레이션 방안
```yaml
Phase 1: 품목기준관리에 "특수 섹션" 설정 추가
- 섹션 유형: 일반, 전개도, BOM 선택 가능
- 전개도 섹션 표시 조건 설정 (부품유형별)
Phase 2: 동적 렌더링 연동
- 품목기준관리 설정에 따라 전개도 섹션 표시
- 필드 구성도 동적으로 변경 가능
```
---
## 4. BOM 섹션 내부 구조
### 파일 위치
`src/components/items/DynamicItemForm/sections/DynamicBOMSection.tsx`
### 하드코딩 내용
#### 4-1. BOM 라인 기본 구조
```typescript
const newLine: BOMLine = {
id: `bom-${Date.now()}`,
childItemCode: '',
childItemName: '',
quantity: 1,
unit: 'EA', // 기본 단위 고정
specification: '',
material: '',
note: '',
partType: '',
bendingDiagram: '',
};
```
#### 4-2. BOM 테이블 컬럼 구조
```typescript
// 고정된 컬럼들
<TableHead>품목코드</TableHead>
<TableHead>품목명</TableHead>
<TableHead>규격</TableHead>
<TableHead>재질</TableHead>
<TableHead className="w-24">수량</TableHead>
<TableHead className="w-20">단위</TableHead>
<TableHead>비고</TableHead>
```
#### 4-3. 품목 검색 결과 매핑
```typescript
const mappedItems: SearchedItem[] = rawItems.map((item) => ({
id: String(item.id),
itemCode: (item.code ?? item.item_code ?? '') as string,
itemName: (item.name ?? item.item_name ?? '') as string,
specification: (item.specification ?? '') as string,
material: (item.material ?? '') as string,
unit: (item.unit ?? 'EA') as string,
partType: (item.part_type ?? '') as string,
bendingDiagram: (item.bending_diagram ?? '') as string,
}));
```
### 문제점
- BOM 컬럼 추가/삭제/순서변경 불가
- 기본 단위 'EA' 고정
- BOM 필드별 필수여부 설정 불가
- 절곡품 전개도 표시 영역 고정
### 마이그레이션 방안
```yaml
Phase 1: 품목기준관리에 "BOM 섹션 설정" 추가
- BOM 컬럼 구성 설정 (표시/숨김, 순서)
- 기본값 설정 (단위, 수량 등)
Phase 2: 동적 BOM 렌더링
- 품목기준관리 설정에 따라 BOM 테이블 렌더링
- 컬럼별 width, 정렬 등 설정 가능
```
---
## 5. 부품유형 판별 로직
### 파일 위치
`src/components/items/DynamicItemForm/index.tsx` (Lines: 444-505)
### 하드코딩 내용
```typescript
// part_type 필드 탐지 (field_key 기반)
const isPartType = fieldKey.includes('part_type') ||
lowerKey.includes('부품유형') ||
lowerKey.includes('부품_유형') ||
fieldName.includes('부품유형') ||
fieldName.includes('부품 유형');
// 부품유형별 판별 (값 기반)
const isBending = currentPartType.includes('절곡') ||
currentPartType.toUpperCase() === 'BENDING';
const isAssembly = currentPartType.includes('조립') ||
currentPartType.toUpperCase() === 'ASSEMBLY';
const isPurchased = currentPartType.includes('구매') ||
currentPartType.toUpperCase() === 'PURCHASED';
```
### 문제점
- 부품유형 키워드 매칭이 코드에 고정
- 새로운 부품유형 추가 시 코드 수정 필요
- 다국어 지원 어려움
### 마이그레이션 방안
```yaml
Phase 1: 품목기준관리에 "부품유형 설정" 추가
- 부품유형 목록 관리 (절곡, 조립, 구매 등)
- 각 부품유형별 특수 처리 설정
Phase 2: 동적 부품유형 판별
- API에서 부품유형 목록과 매칭 키워드 제공
- 코드 기반 판별에서 설정 기반 판별로 전환
```
---
## 6. FG(제품) 시방서/인정서 파일업로드
### 파일 위치
`src/components/items/DynamicItemForm/index.tsx` (Lines: 1446-1494)
### 하드코딩 내용
#### 6-1. 파일업로드 상태 관리
```typescript
// FG(제품) 전용 파일 업로드 상태 관리
const [specificationFile, setSpecificationFile] = useState<File | null>(null);
const [certificationFile, setCertificationFile] = useState<File | null>(null);
```
#### 6-2. 인정 유효기간 종료일 필드 감지
```typescript
// 인정 유효기간 종료일 필드인지 체크 (FG 시방서/인정서 파일 업로드 위치)
const isCertEndDateField = fieldKey.includes('certification_end') ||
fieldKey.includes('인정_유효기간_종료') ||
fieldName.includes('인정 유효기간 종료') ||
fieldName.includes('유효기간 종료');
```
#### 6-3. 시방서/인정서 파일업로드 UI
```typescript
{/* FG(제품) 전용: 인정 유효기간 종료일 다음에 시방서/인정서 파일 업로드 */}
{isCertEndDateField && selectedItemType === 'FG' && (
<div className="mt-4 space-y-4">
{/* 시방서 파일 업로드 */}
<div>
<Label htmlFor="specification_file">시방서 (PDF)</Label>
<div className="mt-1.5">
<Input
id="specification_file"
type="file"
accept=".pdf"
onChange={(e) => {
const file = e.target.files?.[0] || null;
setSpecificationFile(file);
}}
disabled={isSubmitting}
className="cursor-pointer"
/>
{specificationFile && (
<p className="text-xs text-muted-foreground mt-1">
선택된 파일: {specificationFile.name}
</p>
)}
</div>
</div>
{/* 인정서 파일 업로드 */}
<div>
<Label htmlFor="certification_file">인정서 (PDF)</Label>
<div className="mt-1.5">
<Input
id="certification_file"
type="file"
accept=".pdf"
onChange={(e) => {
const file = e.target.files?.[0] || null;
setCertificationFile(file);
}}
disabled={isSubmitting}
className="cursor-pointer"
/>
{certificationFile && (
<p className="text-xs text-muted-foreground mt-1">
선택된 파일: {certificationFile.name}
</p>
)}
</div>
</div>
</div>
)}
```
### 표시 위치
- **조건**: `selectedItemType === 'FG'` (제품 유형일 때만)
- **위치**: 인정 유효기간 종료일 필드 바로 다음
- **파일 형식**: PDF만 허용 (`accept=".pdf"`)
### 문제점
- FG 유형 고정 (다른 품목유형에는 표시 안됨)
- 인정 유효기간 종료일 필드명 매칭이 하드코딩
- 파일 업로드 필드가 품목기준관리에서 설정 불가
### 마이그레이션 방안
```yaml
Phase 1: 품목기준관리에 "파일 첨부 필드" 유형 추가
- 필드 타입: file, image, document 등
- 허용 확장자 설정 (PDF, DOC, 이미지 등)
- 품목유형별 표시 조건 설정
Phase 2: 동적 파일업로드 렌더링
- 품목기준관리 설정에 따라 파일 필드 동적 표시
- 백엔드 파일 저장 API 연동
```
---
## 추가 하드코딩 발견 사항
### 속성 옵션 상태
**파일**: `src/components/items/ItemMasterDataManagement/hooks/useAttributeManagement.ts:77`
```typescript
// 속성 옵션 상태 (기본값 하드코딩 - TODO: 나중에 백엔드 API로 대체)
```
### BOM 가격 정보
**파일**: `src/components/items/ItemForm/hooks/useBOMManagement.ts:89`
```typescript
unitPrice: 0, // TODO: pricing에서 가져오기
```
---
## 종합 마이그레이션 로드맵
### Phase 1: 품목기준관리 API 확장 (백엔드)
1. `item_types` 테이블 - 품목유형 관리
2. `code_generation_rules` 테이블 - 코드 생성 규칙
3. `special_sections` 설정 - 전개도/BOM 섹션 설정
4. `part_types` 테이블 - 부품유형 관리
### Phase 2: 품목기준관리 UI 확장 (프론트엔드)
1. 품목유형 관리 탭 추가
2. 코드생성규칙 설정 UI
3. 특수 섹션 설정 UI
4. 부품유형 관리 UI
### Phase 3: 동적 렌더링 연동
1. 품목유형 API 연동 (ItemTypeSelect)
2. 코드 자동생성 API 연동 (itemCodeGenerator 대체)
3. 전개도 섹션 동적 렌더링
4. BOM 섹션 동적 렌더링
### Phase 4: 프론트엔드 하드코딩 제거
1. 상수 파일들 제거
2. 판별 로직 설정 기반으로 전환
3. 테스트 및 검증
---
## 관련 파일 목록
| 파일 | 하드코딩 항목 |
|------|-------------|
| `src/components/items/ItemTypeSelect.tsx` | 품목유형 목록 |
| `src/components/items/DynamicItemForm/utils/itemCodeGenerator.ts` | PT 코드 생성 규칙, 매핑 테이블 |
| `src/components/items/DynamicItemForm/index.tsx` | FG 품목코드, FG 시방서/인정서 파일업로드, 전개도 섹션, 부품유형 판별 |
| `src/components/items/DynamicItemForm/sections/DynamicBOMSection.tsx` | BOM 구조 |
| `src/components/items/DynamicItemForm/types.ts` | BOMLine 타입 정의 |
> **참고**: `src/components/items/ItemForm/forms/ProductForm.tsx`는 현재 사용되지 않음 (레거시)
---
## 변경 이력
| 날짜 | 내용 |
|-----|------|
| 2025-12-03 | 품목코드/품목명 자동생성 문서화 |
| 2025-12-04 | 전체 하드코딩 항목 종합 문서로 확장 |
| 2025-12-04 | 품목유형, 전개도/바라시, BOM 섹션 추가 |
| 2025-12-04 | 제품(FG) 품목코드 규칙 추가 (품목명=품목코드) - DynamicItemForm으로 이동 |
| 2025-12-04 | FG 전용 시방서/인정서 파일업로드 추가 |