# 입고 프로세스 개선 방안 ## 현재 구조 이해 ### 3단계 데이터 계층 ``` 1. herb_masters (454개) - 성분코드(ingredient_code) 기준 마스터 - 예: 3400H1AHM = 인삼 2. herb_products (53,769개) - 성분코드별 보험코드 매핑 (참조 테이블) - 예: 060600420 = 신흥인삼 → 성분코드 3400H1AHM - 예: 060801010 = 세화인삼 → 성분코드 3400H1AHM 3. herb_items (40개) - 실제 사용/재고 관리 단위 - ingredient_code + insurance_code 모두 보유 ``` ## 현재 문제점 ### 1. Excel 입고 시 보험코드 처리 문제 - Excel에서 보험코드를 숫자로 읽음: `060600420` → `60600420` - DB 매핑 실패 → 새로운 herb_item 생성 (중복/잘못된 데이터) ### 2. 성분코드 연결 누락 - 입고 시 보험코드만으로 herb_item 생성 - ingredient_code 연결 안 됨 - 성분코드 기준 재고 집계 불가 ## 개선된 입고 프로세스 ### 1단계: Excel 읽기 개선 ```python # excel_processor.py 수정 def read_excel(self, file_path): # 제품코드를 문자열로 읽기 self.df_original = pd.read_excel( file_path, dtype={'제품코드': str} ) def process_hanisarang/haninfo(self): # 보험코드 9자리 패딩 처리 if 'insurance_code' in df_mapped.columns: df_mapped['insurance_code'] = df_mapped['insurance_code'].apply( lambda x: str(x).zfill(9) if pd.notna(x) and str(x).isdigit() else x ) ``` ### 2단계: 보험코드 → 성분코드 매핑 ```python # app.py의 upload_purchase_excel 함수 수정 # 1. 보험코드로 herb_products에서 성분코드 찾기 insurance_code = str(row.get('insurance_code')).zfill(9) # 9자리 패딩 cursor.execute(""" SELECT DISTINCT ingredient_code, product_name, company_name FROM herb_products WHERE product_code = ? """, (insurance_code,)) product_info = cursor.fetchone() if product_info: ingredient_code = product_info[0] # 2. herb_items에서 해당 보험코드 제품 확인 cursor.execute(""" SELECT herb_item_id FROM herb_items WHERE insurance_code = ? """, (insurance_code,)) herb_item = cursor.fetchone() if not herb_item: # 3. 새 제품 생성 (ingredient_code 포함!) cursor.execute(""" INSERT INTO herb_items ( ingredient_code, insurance_code, herb_name, specification ) VALUES (?, ?, ?, ?) """, ( ingredient_code, insurance_code, product_info[1], # product_name product_info[2] # company_name )) herb_item_id = cursor.lastrowid else: herb_item_id = herb_item[0] else: # herb_products에 없는 경우 (비보험 약재 등) # 기존 로직 유지 또는 경고 pass ``` ## 성분코드 기준 재고 관리 ### 재고 조회 쿼리 ```sql -- 성분코드별 통합 재고 조회 SELECT hm.ingredient_code, hm.herb_name as master_name, hm.herb_name_hanja, COUNT(DISTINCT hi.herb_item_id) as product_count, COUNT(DISTINCT hi.insurance_code) as insurance_code_count, COUNT(DISTINCT il.lot_id) as lot_count, COALESCE(SUM(il.quantity_onhand), 0) as total_stock, GROUP_CONCAT(DISTINCT hi.specification) as companies FROM herb_masters hm LEFT JOIN herb_items hi ON hm.ingredient_code = hi.ingredient_code LEFT JOIN inventory_lots il ON hi.herb_item_id = il.herb_item_id WHERE hm.is_active = 1 GROUP BY hm.ingredient_code ORDER BY hm.herb_name; ``` ### 조제 시 제품 선택 ```sql -- 성분코드로 가용 제품 조회 SELECT hi.herb_item_id, hi.insurance_code, hi.herb_name as product_name, hi.specification as company, SUM(il.quantity_onhand) as available_stock FROM herb_items hi JOIN inventory_lots il ON hi.herb_item_id = il.herb_item_id WHERE hi.ingredient_code = ? AND il.quantity_onhand > 0 GROUP BY hi.herb_item_id ORDER BY available_stock DESC; ``` ## 구현 우선순위 ### 1. 즉시 수정 (보험코드 문제 해결) - [ ] excel_processor.py: 제품코드 문자열 처리 - [ ] app.py: 9자리 패딩 로직 추가 ### 2. 데이터 정리 - [ ] 기존 잘못된 herb_items 정리 - [ ] ingredient_code 누락된 항목 업데이트 ### 3. 프로세스 개선 - [ ] 입고 시 herb_products 참조하여 성분코드 자동 연결 - [ ] 성분코드 기준 재고 조회 API 추가 ### 4. UI 개선 - [ ] 재고 현황을 성분코드 기준으로 표시 - [ ] 제품별 상세 보기 추가 ## 기대 효과 1. **정확한 매핑**: 보험코드 → 성분코드 자동 연결 2. **통합 재고 관리**: 성분코드 기준으로 여러 제품의 재고 통합 관리 3. **유연한 조제**: 같은 성분의 다른 제품 선택 가능 4. **데이터 일관성**: 표준 코드 체계 준수 ## 추가 고려사항 ### 비보험 약재 처리 - herb_products에 없는 약재 입고 시 - 수동으로 성분코드 매핑 또는 - 별도 비보험 약재 테이블 관리 ### 검증 로직 - 보험코드 형식 검증 (9자리 숫자) - 중복 제품 생성 방지 - 성분코드 매핑 실패 시 경고 ### 마스터 데이터 관리 - herb_products 정기 업데이트 - 신규 보험코드 추가 프로세스 - 성분코드 변경 이력 관리