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

16 KiB
Raw Blame History

품목관리 하드코딩 내역 종합 문서

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

하드코딩 내용

const ITEM_TYPE_LABELS_WITH_ENGLISH: Record<ItemType, string> = {
  FG: '제품 (Finished Goods)',
  PT: '부품 (Part)',
  SM: '부자재 (Sub Material)',
  RM: '원자재 (Raw Material)',
  CS: '소모품 (Consumables)',
};

문제점

  • 품목유형 추가/수정/삭제 불가
  • 각 유형별 표시 순서 고정
  • 영문명 커스터마이징 불가

마이그레이션 방안

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) 품목코드 규칙

// 제품(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. 영문약어 매핑 테이블

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. 절곡품 코드 체계

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. 조립품 설치유형 매핑

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

마이그레이션 방안

Phase 1: 품목기준관리 설정 확장
  - 영문약어 필드 추가 (품목명 필드 옵션에 매핑)
  - 코드생성규칙 설정 UI 추가

Phase 2: 백엔드 이관
  - 품목 저장 시 백엔드에서 코드 자동 생성
  - 순번 관리를 DB 시퀀스로 변경 (동시성 처리)

3. 전개도/바라시 섹션 (조립/절곡)

파일 위치

src/components/items/DynamicItemForm/index.tsx (Lines: 1474-1560)

하드코딩 내용

3-1. 조립품 전개도 섹션 (바라시)

{/* 조립품 전개도 섹션 (PT - 조립 부품 전용) */}
{selectedItemType === 'PT' && isAssemblyPart && assemblyItemNameKey && (
  <BendingDiagramSection
    title="조립품 전개도"
    description="조립품 전개도(바라시)를 그리거나 편집합니다."
    ...
  />
)}

3-2. 절곡품 전개도 섹션

{/* 절곡품 전개도 섹션 (PT - 절곡 부품 전용) */}
{selectedItemType === 'PT' && isBendingPart && bendingFields.material && (
  <BendingDiagramSection
    title="절곡품 전개도"
    description="절곡품 전개도를 그리거나 편집합니다."
    ...
  />
)}

문제점

  • 전개도 섹션 표시 조건이 코드에 고정
  • 조립/절곡 외 다른 부품유형에 전개도 추가 불가
  • 전개도 섹션 필드 구성 변경 불가

데이터 구조 (저장 시)

// 절곡품
{
  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,
}

마이그레이션 방안

Phase 1: 품목기준관리에 "특수 섹션" 설정 추가
  - 섹션 유형: 일반, 전개도, BOM 선택 가능
  - 전개도 섹션 표시 조건 설정 (부품유형별)

Phase 2: 동적 렌더링 연동
  - 품목기준관리 설정에 따라 전개도 섹션 표시
  - 필드 구성도 동적으로 변경 가능

4. BOM 섹션 내부 구조

파일 위치

src/components/items/DynamicItemForm/sections/DynamicBOMSection.tsx

하드코딩 내용

4-1. BOM 라인 기본 구조

const newLine: BOMLine = {
  id: `bom-${Date.now()}`,
  childItemCode: '',
  childItemName: '',
  quantity: 1,
  unit: 'EA',        // 기본 단위 고정
  specification: '',
  material: '',
  note: '',
  partType: '',
  bendingDiagram: '',
};

4-2. BOM 테이블 컬럼 구조

// 고정된 컬럼들
<TableHead>품목코드</TableHead>
<TableHead>품목명</TableHead>
<TableHead>규격</TableHead>
<TableHead>재질</TableHead>
<TableHead className="w-24">수량</TableHead>
<TableHead className="w-20">단위</TableHead>
<TableHead>비고</TableHead>

4-3. 품목 검색 결과 매핑

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 필드별 필수여부 설정 불가
  • 절곡품 전개도 표시 영역 고정

마이그레이션 방안

Phase 1: 품목기준관리에 "BOM 섹션 설정" 추가
  - BOM 컬럼 구성 설정 (표시/숨김, 순서)
  - 기본값 설정 (단위, 수량 등)

Phase 2: 동적 BOM 렌더링
  - 품목기준관리 설정에 따라 BOM 테이블 렌더링
  - 컬럼별 width, 정렬 등 설정 가능

5. 부품유형 판별 로직

파일 위치

src/components/items/DynamicItemForm/index.tsx (Lines: 444-505)

하드코딩 내용

// 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';

문제점

  • 부품유형 키워드 매칭이 코드에 고정
  • 새로운 부품유형 추가 시 코드 수정 필요
  • 다국어 지원 어려움

마이그레이션 방안

Phase 1: 품목기준관리에 "부품유형 설정" 추가
  - 부품유형 목록 관리 (절곡, 조립, 구매 등)
  - 각 부품유형별 특수 처리 설정

Phase 2: 동적 부품유형 판별
  - API에서 부품유형 목록과 매칭 키워드 제공
  - 코드 기반 판별에서 설정 기반 판별로 전환

6. FG(제품) 시방서/인정서 파일업로드

파일 위치

src/components/items/DynamicItemForm/index.tsx (Lines: 1446-1494)

하드코딩 내용

6-1. 파일업로드 상태 관리

// FG(제품) 전용 파일 업로드 상태 관리
const [specificationFile, setSpecificationFile] = useState<File | null>(null);
const [certificationFile, setCertificationFile] = useState<File | null>(null);

6-2. 인정 유효기간 종료일 필드 감지

// 인정 유효기간 종료일 필드인지 체크 (FG 시방서/인정서 파일 업로드 위치)
const isCertEndDateField = fieldKey.includes('certification_end') ||
                   fieldKey.includes('인정_유효기간_종료') ||
                   fieldName.includes('인정 유효기간 종료') ||
                   fieldName.includes('유효기간 종료');

6-3. 시방서/인정서 파일업로드 UI

{/* 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 유형 고정 (다른 품목유형에는 표시 안됨)
  • 인정 유효기간 종료일 필드명 매칭이 하드코딩
  • 파일 업로드 필드가 품목기준관리에서 설정 불가

마이그레이션 방안

Phase 1: 품목기준관리에 "파일 첨부 필드" 유형 추가
  - 필드 타입: file, image, document 등
  - 허용 확장자 설정 (PDF, DOC, 이미지 등)
  - 품목유형별 표시 조건 설정

Phase 2: 동적 파일업로드 렌더링
  - 품목기준관리 설정에 따라 파일 필드 동적 표시
  - 백엔드 파일 저장 API 연동

추가 하드코딩 발견 사항

속성 옵션 상태

파일: src/components/items/ItemMasterDataManagement/hooks/useAttributeManagement.ts:77

// 속성 옵션 상태 (기본값 하드코딩 - TODO: 나중에 백엔드 API로 대체)

BOM 가격 정보

파일: src/components/items/ItemForm/hooks/useBOMManagement.ts:89

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 전용 시방서/인정서 파일업로드 추가