#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 한의사랑 카탈로그 데이터 import 및 가격 매칭 """ import sqlite3 import re def get_connection(): """데이터베이스 연결""" return sqlite3.connect('database/kdrug.db') def parse_catalog_data(): """제공된 카탈로그 데이터 파싱""" raw_data = """갈근.각5 배송중 42,000 400 0 롯데택배256733159384배송조회 감초.1호[야생](1kg)5 배송중 110,500 0 건강10 배송중 62,000 600 건강.土3 배송중 77,100 750 계지5 배송중 14,500 100 구기자(영하)(1kg)3 배송중 53,700 510 길경.片[특]3 배송중 15,900 0 대추(절편)(1kg)5 배송중 100,000 1,000 마황(1kg)5 배송중 48,000 0 반하생강백반제(1kg)3 배송중 101,100 990 백출.당[1kg]2 배송중 23,600 0 복령(1kg)5 배송중 57,500 550 석고[통포장](kg)4 배송중 18,800 160 세신.中3 배송중 193,500 0 숙지황(9증)(신흥.1kg)[완]5 배송중 100,000 1,000 오미자<토매지>(1kg)2 배송중 35,000 340 용안육.名품(1kg)3 배송중 62,100 600 육계.YB25 배송중 36,500 350 일당귀.中(1kg)5 배송중 64,500 600 자소엽.土3 배송중 20,700 180 작약(1kg)3 배송중 56,100 540 작약주자.土[酒炙]3 배송중 36,900 360 전호[재배]3 배송중 21,000 210 지각3 배송중 15,000 150 지황.건[회](1kg)1 배송중 11,500 110 진피.비열[非熱](1kg)5 배송중 68,500 0 창출[북창출.재배](1kg)3 배송중 40,500 0 천궁.일<토매지>(1kg)3 배송중 35,700 330 황기(직절.小)(1kg)3 배송중 29,700 270""" items = [] for line in raw_data.split('\n'): if not line.strip(): continue # 택배 추적번호 제거 line = re.sub(r'롯데택배\d+배송조회', '', line) parts = line.split('\t') if len(parts) >= 4: # 약재명 추출 (뒤의 수량 숫자 제거) raw_name = re.sub(r'\d+$', '', parts[0]) # 가격 파싱 (콤마 제거) total_price = int(parts[2].replace(',', '')) # g당 단가 if len(parts) >= 5 and parts[4] != '0': unit_price = int(parts[4].replace(',', '')) else: # g당 단가가 0이면 총액에서 계산 (1kg 기준) if '1kg' in raw_name or 'kg' in raw_name: unit_price = total_price / 1000 else: unit_price = total_price / 1000 # 기본적으로 1kg로 가정 items.append({ 'raw_name': raw_name.strip(), 'total_price': total_price, 'unit_price': unit_price, 'status': parts[1] if len(parts) > 1 else '배송중' }) return items def import_to_catalog(): """카탈로그 데이터를 DB에 저장""" conn = get_connection() cursor = conn.cursor() print("\n" + "="*80) print("한의사랑 카탈로그 데이터 Import") print("="*80) # 한의사랑 supplier_id 조회 cursor.execute("SELECT supplier_id FROM suppliers WHERE name = '한의사랑'") result = cursor.fetchone() if not result: # 한의사랑 공급처 생성 cursor.execute(""" INSERT INTO suppliers (name, is_active) VALUES ('한의사랑', 1) """) supplier_id = cursor.lastrowid print(f"한의사랑 공급처 생성 (ID: {supplier_id})") else: supplier_id = result[0] print(f"한의사랑 공급처 확인 (ID: {supplier_id})") # 기존 데이터 삭제 cursor.execute("DELETE FROM supplier_product_catalog WHERE supplier_id = ?", (supplier_id,)) # 카탈로그 데이터 파싱 items = parse_catalog_data() print(f"\n총 {len(items)}개 항목을 파싱했습니다.") print("-" * 60) # 데이터 삽입 for item in items: try: cursor.execute(""" INSERT INTO supplier_product_catalog (supplier_id, raw_name, unit_price, package_unit, stock_status, last_updated) VALUES (?, ?, ?, '1kg', ?, date('now')) """, (supplier_id, item['raw_name'], item['unit_price'], item['status'])) print(f"추가: {item['raw_name']:30s} | {item['unit_price']:8.1f}원/g | {item['status']}") except sqlite3.IntegrityError: print(f"중복: {item['raw_name']}") conn.commit() # 저장된 데이터 확인 cursor.execute(""" SELECT COUNT(*) FROM supplier_product_catalog WHERE supplier_id = ? """, (supplier_id,)) count = cursor.fetchone()[0] print(f"\n한의사랑 카탈로그에 {count}개 항목이 저장되었습니다.") conn.close() return items def match_with_inventory(): """현재 inventory_lots와 가격 매칭""" conn = get_connection() cursor = conn.cursor() print("\n" + "="*80) print("Inventory Lots와 가격 매칭") print("="*80) # 휴먼허브 inventory lots 조회 cursor.execute(""" SELECT l.lot_id, h.herb_name, l.unit_price_per_g, l.origin_country, s.name as supplier_name FROM inventory_lots l JOIN herb_items h ON l.herb_item_id = h.herb_item_id JOIN purchase_receipt_lines prl ON l.receipt_line_id = prl.line_id JOIN purchase_receipts pr ON prl.receipt_id = pr.receipt_id JOIN suppliers s ON pr.supplier_id = s.supplier_id WHERE l.display_name IS NULL ORDER BY h.herb_name, l.unit_price_per_g """) lots = cursor.fetchall() print(f"\ndisplay_name이 없는 로트: {len(lots)}개\n") matched_count = 0 no_match = [] for lot in lots: lot_id, herb_name, unit_price, origin, supplier = lot # 한의사랑 카탈로그에서 비슷한 가격 찾기 (±10% 허용) cursor.execute(""" SELECT raw_name, unit_price FROM supplier_product_catalog spc JOIN suppliers s ON spc.supplier_id = s.supplier_id WHERE s.name = '한의사랑' AND ABS(spc.unit_price - ?) / ? < 0.1 ORDER BY ABS(spc.unit_price - ?) LIMIT 5 """, (unit_price, unit_price, unit_price)) matches = cursor.fetchall() if matches: print(f"\nLot #{lot_id}: {herb_name} ({unit_price:.1f}원/g, {origin})") print(" 매칭 후보:") best_match = None for match in matches: match_name, match_price = match diff_percent = abs(match_price - unit_price) / unit_price * 100 print(f" - {match_name:30s} | {match_price:8.1f}원/g | 차이: {diff_percent:.1f}%") # 약재명에서 핵심 단어 추출하여 매칭 herb_core = herb_name.replace('휴먼', '').replace('신흥', '') if herb_core in match_name or any(keyword in match_name for keyword in [herb_core[:2], herb_core[-2:]]): if not best_match or abs(match_price - unit_price) < abs(best_match[1] - unit_price): best_match = match if best_match: # display_name 업데이트 cursor.execute(""" UPDATE inventory_lots SET display_name = ? WHERE lot_id = ? """, (best_match[0], lot_id)) # lot_variants 추가/업데이트 try: cursor.execute(""" INSERT INTO lot_variants (lot_id, raw_name, parsed_at, parsed_method) VALUES (?, ?, datetime('now'), 'catalog_price_match') """, (lot_id, best_match[0])) except sqlite3.IntegrityError: cursor.execute(""" UPDATE lot_variants SET raw_name = ?, parsed_at = datetime('now'), parsed_method = 'catalog_price_match' WHERE lot_id = ? """, (best_match[0], lot_id)) print(f" ✓ 매칭: {best_match[0]}") matched_count += 1 else: print(" ✗ 적합한 매칭 없음") no_match.append((lot_id, herb_name, unit_price, origin)) else: no_match.append((lot_id, herb_name, unit_price, origin)) conn.commit() print("\n" + "="*80) print("매칭 결과") print("="*80) print(f"✓ 매칭 성공: {matched_count}개") print(f"✗ 매칭 실패: {len(no_match)}개") if no_match: print("\n매칭 실패한 로트:") for lot in no_match: print(f" Lot #{lot[0]}: {lot[1]:20s} | {lot[2]:8.1f}원/g | {lot[3]}") # 최종 결과 확인 cursor.execute(""" SELECT COUNT(*) as total, COUNT(display_name) as with_display FROM inventory_lots """) result = cursor.fetchone() print(f"\n전체 로트: {result[0]}개") print(f"display_name 설정됨: {result[1]}개") conn.close() def main(): """메인 실행""" print("\n한의사랑 카탈로그 데이터 Import 및 매칭") print("="*80) # 1. 카탈로그 데이터 import items = import_to_catalog() # 2. inventory lots와 매칭 match_with_inventory() print("\n완료!") if __name__ == "__main__": main()