feat: 입고 시 herb_products에서 자동 정보 매핑

주요 개선사항:
1. 보험코드로 herb_products 테이블에서 자동 정보 조회
   - 성분코드(ingredient_code) 자동 매핑
   - 회사명(specification) 자동 입력
   - 표준 제품명 자동 적용

2. 입고 날짜 처리 버그 수정
   - pandas groupby 튜플 문제 해결
   - receipt_date 문자열 변환 처리
   - 입고번호 정상 생성 (PR-YYYYMMDD-XXXX)

3. 데이터 타입 문제 수정
   - total_amount numpy 타입을 float로 변환
   - JSON 직렬화 오류 방지

이제 Excel 입고 시 보험코드만으로 모든 정보 자동 입력

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
시골약사 2026-02-16 14:37:52 +00:00
parent 1198c22083
commit 849c2dd561

101
app.py
View File

@ -545,12 +545,18 @@ def upload_purchase_excel():
return jsonify({'success': False, 'error': '유효하지 않은 도매상입니다'}), 400
# 날짜별로 그룹화 (도매상은 이미 선택됨)
grouped = df.groupby(['receipt_date'])
grouped = df.groupby('receipt_date') # 리스트 대신 문자열로 변경
for receipt_date, group in grouped:
# receipt_date가 튜플인 경우 처리
if isinstance(receipt_date, tuple):
receipt_date = receipt_date[0]
# receipt_date를 문자열로 확실히 변환
receipt_date_str = str(receipt_date)
# 입고장 번호 생성 (PR-YYYYMMDD-XXXX)
date_str = str(receipt_date).replace('-', '')
date_str = receipt_date_str.replace('-', '')
# 해당 날짜의 최대 번호 찾기
cursor.execute("""
@ -564,30 +570,93 @@ def upload_purchase_excel():
receipt_no = f"PR-{date_str}-{next_num:04d}"
# 입고장 헤더 생성
total_amount = group['total_amount'].sum()
total_amount = float(group['total_amount'].sum()) # float로 변환하여 numpy 타입 문제 해결
cursor.execute("""
INSERT INTO purchase_receipts (supplier_id, receipt_date, receipt_no, total_amount, source_file)
VALUES (?, ?, ?, ?, ?)
""", (supplier_id, str(receipt_date), receipt_no, total_amount, filename))
""", (supplier_id, receipt_date_str, receipt_no, total_amount, filename))
receipt_id = cursor.lastrowid
# 입고장 라인 생성
for _, row in group.iterrows():
# 약재 확인/생성
cursor.execute("""
SELECT herb_item_id FROM herb_items
WHERE insurance_code = ? OR herb_name = ?
""", (row.get('insurance_code'), row['herb_name']))
herb = cursor.fetchone()
insurance_code = row.get('insurance_code')
if not herb:
# 보험코드가 있는 경우 herb_products에서 정보 가져오기
if insurance_code:
cursor.execute("""
INSERT INTO herb_items (insurance_code, herb_name)
VALUES (?, ?)
""", (row.get('insurance_code'), row['herb_name']))
herb_item_id = cursor.lastrowid
SELECT DISTINCT
hp.ingredient_code,
hp.product_name,
hp.company_name
FROM herb_products hp
WHERE hp.product_code = ?
""", (insurance_code,))
product_info = cursor.fetchone()
if product_info:
ingredient_code = product_info[0]
product_name = product_info[1]
company_name = product_info[2]
# herb_items에서 해당 보험코드 제품 확인
cursor.execute("""
SELECT herb_item_id FROM herb_items
WHERE insurance_code = ?
""", (insurance_code,))
herb = cursor.fetchone()
if not herb:
# 새 제품 생성 (ingredient_code, company_name 포함)
cursor.execute("""
INSERT INTO herb_items (
ingredient_code,
insurance_code,
herb_name,
specification
) VALUES (?, ?, ?, ?)
""", (ingredient_code, insurance_code, product_name, company_name))
herb_item_id = cursor.lastrowid
else:
herb_item_id = herb[0]
# 기존 제품의 ingredient_code가 없으면 업데이트
cursor.execute("""
UPDATE herb_items
SET ingredient_code = COALESCE(ingredient_code, ?),
specification = COALESCE(specification, ?)
WHERE herb_item_id = ?
""", (ingredient_code, company_name, herb_item_id))
else:
# herb_products에 없는 경우 기존 로직
cursor.execute("""
SELECT herb_item_id FROM herb_items
WHERE insurance_code = ? OR herb_name = ?
""", (insurance_code, row['herb_name']))
herb = cursor.fetchone()
if not herb:
cursor.execute("""
INSERT INTO herb_items (insurance_code, herb_name)
VALUES (?, ?)
""", (insurance_code, row['herb_name']))
herb_item_id = cursor.lastrowid
else:
herb_item_id = herb[0]
else:
herb_item_id = herb[0]
# 보험코드가 없는 경우 약재명으로만 처리
cursor.execute("""
SELECT herb_item_id FROM herb_items
WHERE herb_name = ?
""", (row['herb_name'],))
herb = cursor.fetchone()
if not herb:
cursor.execute("""
INSERT INTO herb_items (herb_name)
VALUES (?)
""", (row['herb_name'],))
herb_item_id = cursor.lastrowid
else:
herb_item_id = herb[0]
# 단가 계산 (총액 / 수량)
quantity = float(row['quantity'])