feat: 의약품 마스터 DB 연동 (ATTACH DATABASE)

- medicine_master.db (305,522행) CSV→SQLite 변환 완료
- get_db()에서 ATTACH DATABASE로 자동 연결
- GET /api/medicine-master/search: 상품명/업체명/표준코드 검색
- GET /api/medicine-master/categories: 전문일반구분별 통계
- config.py에 MEDICINE_MASTER_PATH 추가
- 취소된 제품 자동 필터링, 카테고리 필터 지원

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
시골약사 2026-02-19 15:19:14 +00:00
parent 725f14c59a
commit c0d55f8e16
2 changed files with 73 additions and 1 deletions

73
app.py
View File

@ -15,7 +15,7 @@ from werkzeug.utils import secure_filename
import json
from contextlib import contextmanager
from excel_processor import ExcelProcessor
from config import DATABASE_PATH, STATIC_PATH, TEMPLATES_PATH
from config import DATABASE_PATH, MEDICINE_MASTER_PATH, STATIC_PATH, TEMPLATES_PATH
# Flask 앱 초기화
app = Flask(__name__, static_folder='static', template_folder='templates')
@ -42,6 +42,10 @@ def get_db():
conn = sqlite3.connect(app.config['DATABASE'])
conn.row_factory = sqlite3.Row # 딕셔너리 형태로 반환
conn.execute('PRAGMA foreign_keys = ON') # 외래키 제약 활성화
# 의약품 마스터 DB 연결 (읽기 전용 참조)
medicine_db = str(MEDICINE_MASTER_PATH)
if os.path.exists(medicine_db):
conn.execute(f"ATTACH DATABASE '{medicine_db}' AS med_master")
try:
yield conn
conn.commit()
@ -3768,6 +3772,73 @@ def convert_to_otc(compound_id):
except Exception as e:
return jsonify({'error': str(e)}), 500
# ==================== 의약품 마스터 검색 API ====================
@app.route('/api/medicine-master/search', methods=['GET'])
def search_medicine_master():
"""의약품 마스터 검색 (medicine_master.db ATTACH 활용)"""
try:
q = request.args.get('q', '').strip()
category = request.args.get('category', '') # 전문일반구분 필터
limit = min(int(request.args.get('limit', 50)), 200)
if not q or len(q) < 2:
return jsonify({'success': False, 'error': '검색어는 2자 이상 입력하세요'}), 400
with get_db() as conn:
cursor = conn.cursor()
where_clauses = ["(m.product_name LIKE ? OR m.company_name LIKE ? OR m.standard_code LIKE ? OR m.notes LIKE ?)"]
params = [f'%{q}%', f'%{q}%', f'%{q}%', f'%{q}%']
if category:
where_clauses.append("m.category = ?")
params.append(category)
# 취소된 제품 제외
where_clauses.append("(m.cancel_date IS NULL OR m.cancel_date = '')")
params.append(limit)
cursor.execute(f"""
SELECT m.id, m.product_name, m.company_name, m.spec,
m.total_quantity, m.form_type, m.package_type,
m.item_std_code, m.category, m.representative_code,
m.standard_code, m.ingredient_name_code, m.notes,
m.atc_code
FROM med_master.medicine_master m
WHERE {' AND '.join(where_clauses)}
ORDER BY m.product_name, m.spec
LIMIT ?
""", params)
results = [dict(row) for row in cursor.fetchall()]
return jsonify({'success': True, 'data': results, 'count': len(results)})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/api/medicine-master/categories', methods=['GET'])
def get_medicine_categories():
"""의약품 마스터 카테고리 목록 (전문일반구분)"""
try:
with get_db() as conn:
cursor = conn.cursor()
cursor.execute("""
SELECT category, COUNT(*) as cnt
FROM med_master.medicine_master
WHERE category != '' AND (cancel_date IS NULL OR cancel_date = '')
GROUP BY category
ORDER BY cnt DESC
""")
categories = [{'name': row['category'], 'count': row['cnt']} for row in cursor.fetchall()]
return jsonify({'success': True, 'data': categories})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
if __name__ == '__main__':
# 데이터베이스 초기화
if not os.path.exists(app.config['DATABASE']):

View File

@ -12,6 +12,7 @@ PROJECT_ROOT = Path(__file__).parent
# 데이터베이스 경로 - 항상 절대 경로 사용
DATABASE_PATH = PROJECT_ROOT / 'database' / 'kdrug.db'
MEDICINE_MASTER_PATH = PROJECT_ROOT / 'database' / 'medicine_master.db'
# 기타 자주 사용하는 경로들
STATIC_PATH = PROJECT_ROOT / 'static'