#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 커스텀 처방 감지 유틸리티 조제 시 원 처방과 다른 구성인지 확인 """ import sqlite3 from typing import Dict, List, Tuple def get_connection(): """데이터베이스 연결""" return sqlite3.connect('database/kdrug.db') def check_custom_prescription(compound_id: int) -> Tuple[bool, Dict]: """ 조제가 원 처방과 다른지 확인 Returns: (is_custom, differences_dict) """ conn = get_connection() cursor = conn.cursor() # 1. compound의 formula_id 가져오기 cursor.execute(""" SELECT c.formula_id, f.formula_name FROM compounds c JOIN formulas f ON c.formula_id = f.formula_id WHERE c.compound_id = ? """, (compound_id,)) result = cursor.fetchone() if not result: conn.close() return False, {"error": "Compound not found"} formula_id, formula_name = result # 2. 원 처방의 구성 약재 cursor.execute(""" SELECT fi.herb_item_id, h.herb_name, fi.grams_per_cheop FROM formula_ingredients fi JOIN herb_items h ON fi.herb_item_id = h.herb_item_id WHERE fi.formula_id = ? ORDER BY fi.herb_item_id """, (formula_id,)) original_ingredients = {row[0]: { 'herb_name': row[1], 'grams_per_cheop': row[2] } for row in cursor.fetchall()} # 3. 실제 조제된 구성 약재 cursor.execute(""" SELECT ci.herb_item_id, h.herb_name, ci.grams_per_cheop FROM compound_ingredients ci JOIN herb_items h ON ci.herb_item_id = h.herb_item_id WHERE ci.compound_id = ? ORDER BY ci.herb_item_id """, (compound_id,)) actual_ingredients = {row[0]: { 'herb_name': row[1], 'grams_per_cheop': row[2] } for row in cursor.fetchall()} conn.close() # 4. 비교 분석 differences = { 'formula_name': formula_name, 'added': [], 'removed': [], 'modified': [], 'is_custom': False } # 추가된 약재 for herb_id, info in actual_ingredients.items(): if herb_id not in original_ingredients: differences['added'].append({ 'herb_id': herb_id, 'herb_name': info['herb_name'], 'grams_per_cheop': info['grams_per_cheop'] }) differences['is_custom'] = True # 제거된 약재 for herb_id, info in original_ingredients.items(): if herb_id not in actual_ingredients: differences['removed'].append({ 'herb_id': herb_id, 'herb_name': info['herb_name'], 'grams_per_cheop': info['grams_per_cheop'] }) differences['is_custom'] = True # 용량 변경된 약재 for herb_id in set(original_ingredients.keys()) & set(actual_ingredients.keys()): orig_grams = original_ingredients[herb_id]['grams_per_cheop'] actual_grams = actual_ingredients[herb_id]['grams_per_cheop'] if abs(orig_grams - actual_grams) > 0.01: # 부동소수점 오차 고려 differences['modified'].append({ 'herb_id': herb_id, 'herb_name': original_ingredients[herb_id]['herb_name'], 'original_grams': orig_grams, 'actual_grams': actual_grams, 'difference': actual_grams - orig_grams }) differences['is_custom'] = True return differences['is_custom'], differences def generate_custom_summary(differences: Dict) -> str: """커스텀 내역을 요약 문자열로 생성""" summary_parts = [] # 추가 if differences['added']: added_herbs = [f"{item['herb_name']} {item['grams_per_cheop']}g" for item in differences['added']] summary_parts.append(f"추가: {', '.join(added_herbs)}") # 제거 if differences['removed']: removed_herbs = [item['herb_name'] for item in differences['removed']] summary_parts.append(f"제거: {', '.join(removed_herbs)}") # 수정 if differences['modified']: modified_herbs = [f"{item['herb_name']} {item['original_grams']}g→{item['actual_grams']}g" for item in differences['modified']] summary_parts.append(f"변경: {', '.join(modified_herbs)}") return " | ".join(summary_parts) if summary_parts else "표준 처방" def list_all_custom_prescriptions(): """모든 커스텀 처방 찾기""" conn = get_connection() cursor = conn.cursor() # 모든 조제 목록 cursor.execute(""" SELECT c.compound_id, c.compound_date, p.name as patient_name, f.formula_name FROM compounds c LEFT JOIN patients p ON c.patient_id = p.patient_id JOIN formulas f ON c.formula_id = f.formula_id ORDER BY c.compound_date DESC """) compounds = cursor.fetchall() conn.close() custom_compounds = [] for compound in compounds: compound_id = compound[0] is_custom, differences = check_custom_prescription(compound_id) if is_custom: custom_compounds.append({ 'compound_id': compound_id, 'compound_date': compound[1], 'patient_name': compound[2], 'formula_name': compound[3], 'summary': generate_custom_summary(differences), 'differences': differences }) return custom_compounds def demo(): """데모 실행""" print("\n" + "="*80) print("커스텀 처방 감지 시스템") print("="*80) # 전체 커스텀 처방 검색 custom_prescriptions = list_all_custom_prescriptions() if not custom_prescriptions: print("\n조제 내역이 없거나 모든 조제가 표준 처방입니다.") # 테스트용 샘플 데이터 표시 print("\n[시뮬레이션] 만약 십전대보탕에 구기자를 추가했다면:") print("-" * 60) sample_diff = { 'formula_name': '십전대보탕', 'added': [{'herb_name': '구기자', 'grams_per_cheop': 3}], 'removed': [], 'modified': [{'herb_name': '인삼', 'original_grams': 5, 'actual_grams': 7}], 'is_custom': True } summary = generate_custom_summary(sample_diff) print(f"처방: 십전대보탕 (가감방)") print(f"변경 내역: {summary}") print("\n환자 기록 표시:") print(" 2024-02-17 십전대보탕 가감방 20첩") print(f" └─ {summary}") else: print(f"\n총 {len(custom_prescriptions)}개의 커스텀 처방이 발견되었습니다.\n") for cp in custom_prescriptions: print(f"조제 #{cp['compound_id']} | {cp['compound_date']} | {cp['patient_name']}") print(f" 처방: {cp['formula_name']} (가감방)") print(f" 변경: {cp['summary']}") print() if __name__ == "__main__": demo()